From 3c168fbb6691a779fbfce3479d7bbd4efd5ee221 Mon Sep 17 00:00:00 2001 From: tjhunt Date: Fri, 11 Jul 2008 17:03:43 +0000 Subject: [PATCH] MDL-15543 - Display the quiz navigation on the attempt.php page and most of MDL-15540 - Write code to render the navigation panel - it does it all apart from working out the correct state in which to show each button, and apply appropriate styles as a result. --- lang/en_utf8/quiz.php | 2 + mod/quiz/attempt.php | 46 +++++++++++--- mod/quiz/attemptlib.php | 104 ++++++++++++++++++++++++++++--- mod/quiz/quiz.js | 10 --- theme/standard/styles_layout.css | 34 ++++++++-- 5 files changed, 165 insertions(+), 31 deletions(-) diff --git a/lang/en_utf8/quiz.php b/lang/en_utf8/quiz.php index e3aefdec6c..cb4c3f01d4 100644 --- a/lang/en_utf8/quiz.php +++ b/lang/en_utf8/quiz.php @@ -212,6 +212,7 @@ in course \'$a->coursename\' You can review this attempt at $a->quizreviewurl.'; $string['emailnotifysubject'] = '$a->studentname has completed quiz $a->quizname'; +$string['endtest'] = 'End test ...'; $string['errorinquestion'] = 'Error in question'; $string['errormissingquestion'] = 'Error: The system is missing the question with id $a'; $string['errornotnumbers'] = 'Error - answers must be numeric'; @@ -467,6 +468,7 @@ $string['quiznotavailable'] = 'The quiz will not be available until $a'; $string['quizopen'] = 'Open the quiz'; $string['quizopens'] = 'Quiz opens'; $string['quizopenedon'] = 'This quiz opened at $a'; +$string['quiznavigation'] = 'Quiz navigation'; $string['quizsettings'] = 'Quiz settings'; $string['quiztimelimit'] = 'Time limit: $a'; $string['quiztimer'] = 'Quiz Timer'; diff --git a/mod/quiz/attempt.php b/mod/quiz/attempt.php index 4508d5bacc..c521d62a69 100644 --- a/mod/quiz/attempt.php +++ b/mod/quiz/attempt.php @@ -36,6 +36,23 @@ $attemptobj = new quiz_attempt($attemptid); +/// Because IE is buggy (see http://www.peterbe.com/plog/button-tag-in-IE) we cannot +/// do the quiz navigation buttons as . +/// Instead we have to do them as - +/// at lest that seemed like the least horrible work-around to me. Therefore, we need to +/// intercept gotopageN parameters here, and adjust $pgae accordingly. + if (optional_param('gotosummary', false, PARAM_BOOL)) { + $page = -1; + } else { + $numpagesinquiz = $attemptobj->get_num_pages(); + for ($i = 0; $i < $numpagesinquiz; $i++) { + if (optional_param('gotopage' . $i, false, PARAM_BOOL)) { + $page = $i; + break; + } + } + } + /// We treat automatically closed attempts just like normally closed attempts if ($timeup) { $finishattempt = 1; @@ -275,9 +292,17 @@ if ($page == -1) { } echo '
'; -/// Print the navigation panel if required - // TODO!!! - quiz_print_navigation_panel($page, $attemptobj->get_num_pages()); +/// Print the navigation panel in a left column. + print_container_start(); + echo '
'; + $attemptobj->print_navigation_panel('quiz_attempt_nav_panel', $page); + echo '
'; + print_container_end(); + +/// Start the main column. + echo '
'; + print_container_start(); + echo skip_main_destination(); /// Print all the questions foreach ($attemptobj->get_question_ids($page) as $id) { @@ -285,13 +310,13 @@ if ($page == -1) { } /// Print a link to the next page. - echo "
\n"; + echo '
'; if ($attemptobj->is_last_page($page)) { - $nextpage = -1; + $nextpage = 'gotosummary'; } else { - $nextpage = $page + 1; + $nextpage = 'gotopage' . ($page + 1); } - echo link_arrow_right(get_string('next'), 'javascript:navigate(' . $nextpage . ')'); + echo ''; echo "
"; // Finish the form @@ -306,6 +331,13 @@ if ($page == -1) { echo "\n"; + // End middle column. + print_container_end(); + echo '
'; + + echo '
'; + echo '
'; + // Finish the page $accessmanager->show_attempt_timer_if_needed($attemptobj->get_attempt(), time()); if ($accessmanager->securewindow_required($attemptobj->is_preview_user())) { diff --git a/mod/quiz/attemptlib.php b/mod/quiz/attemptlib.php index 490ceba307..ac5d693f7a 100644 --- a/mod/quiz/attemptlib.php +++ b/mod/quiz/attemptlib.php @@ -165,7 +165,6 @@ class quiz { * @return object the question object with that id. */ public function get_question($id) { - $this->ensure_question_loaded($id); return $this->questions[$id]; } @@ -254,7 +253,7 @@ class quiz { */ public function attempt_url($attemptid) { global $CFG; - return $CFG->wwwroot . '/mod/quiz/attempt.php?attempt=' . $attemptid . '&page=0'; + return $CFG->wwwroot . '/mod/quiz/attempt.php?attempt=' . $attemptid; } /** @@ -555,7 +554,7 @@ class quiz_attempt extends quiz { */ public function attempt_url($questionid = 0, $page = -1) { global $CFG; - return $CFG->wwwroot . '/mod/quiz/attempt.php?attempt=' . $this->attempt->id . '&' . + return $CFG->wwwroot . '/mod/quiz/attempt.php?attempt=' . $this->attempt->id . $this->page_and_question_fragment($questionid, $page); } @@ -582,7 +581,7 @@ class quiz_attempt extends quiz { if (is_null($otherattemptid)) { $otherattemptid = $this->attempt->id; } - return $CFG->wwwroot . '/mod/quiz/review.php?attempt=' . $otherattemptid . '&' . + return $CFG->wwwroot . '/mod/quiz/review.php?attempt=' . $otherattemptid . $this->page_and_question_fragment($questionid, $page, $showall); } @@ -614,7 +613,11 @@ class quiz_attempt extends quiz { quiz_send_notification_emails($this->course, $this->quiz, $this->attempt, $this->context, $this->cm); } - + + public function print_navigation_panel($panelclass, $page) { + $panel = new quiz_attempt_nav_panel($this, $this->get_review_options(), $page); + $panel->display(); + } // Private methods ===================================================================== // Check that the state of a particular question is loaded, and if not throw an exception. @@ -641,7 +644,7 @@ class quiz_attempt extends quiz { * @return string bit to add to the end of a URL. */ private function page_and_question_fragment($questionid, $page, $showall = false) { - if ($page = -1) { + if ($page == -1) { if ($questionid) { $page = $this->questions[$questionid]->_page; } else { @@ -657,10 +660,9 @@ class quiz_attempt extends quiz { } $param = ''; if ($showall) { - $param = 'showall=1'; - } else if (/*$page > 1*/ true) { - // TODO currently needed by the navigate JS, but clean this up later. - $param = 'page=' . $page; + $param = '&showall=1'; + } else if ($page > 0) { + $param = '&page=' . $page; } return $param . $fragment; } @@ -722,4 +724,86 @@ class quiz_attempt_question_iterator implements Iterator { return $this->current() !== false; } } + +abstract class quiz_nav_panel_base { + protected $attemptobj; + protected $options; + protected $page; + + protected function __construct(quiz_attempt $attemptobj, $options, $page) { + $this->attemptobj = $attemptobj; + $this->options = $options; + $this->page = $page; + } + + protected function get_question_buttons() { + $html = '
'; + foreach ($this->attemptobj->get_question_iterator() as $number => $question) { + $html .= $this->get_question_button($number, $question); + } + $html .= '
'; + return $html; + } + + abstract protected function get_question_button($number, $question); + + abstract protected function get_end_bits(); + + protected function get_question_state($question) { + $state = 'todo'; // TODO + if ($question->_page == $this->page) { + $state .= ' thispage'; + } + return $state; + } + + public function display() { + $strquiznavigation = get_string('quiznavigation', 'quiz'); + $content = $this->get_question_buttons() . $this->get_end_bits(); + print_side_block($strquiznavigation, $content, NULL, NULL, '', array('id' => 'quiznavigation'), $strquiznavigation); + } +} + +class quiz_attempt_nav_panel extends quiz_nav_panel_base { + public function __construct(quiz_attempt $attemptobj, $options, $page) { + parent::__construct($attemptobj, $options, $page); + } + + protected function get_question_button($number, $question) { + $questionsonpage = $this->attemptobj->get_question_ids($question->_page); + $onclick = ''; + if ($question->id != reset($questionsonpage)) { + $onclick = ' onclick="form.action = form.action + \'#q' . $question->id . + '\'; return true;"'; + } + return ''; + } + + protected function get_end_bits() { + return ''; + } +} + +class quiz_review_nav_panel extends quiz_nav_panel_base { + public function __construct(quiz_attempt $attemptobj, $options, $page) { + parent::__construct($attemptobj, $options, $page); + } + + protected function get_question_button($number, $question) { + return '' . $number . ''; + } + + protected function get_end_bits() { + $html = '' . + get_string('showall', 'quiz') . ''; + $html .= '' . + get_string('finishreview', 'quiz') . ''; + return $html; + } +} ?> \ No newline at end of file diff --git a/mod/quiz/quiz.js b/mod/quiz/quiz.js index 2ced50fc1c..6201bbffec 100644 --- a/mod/quiz/quiz.js +++ b/mod/quiz/quiz.js @@ -6,16 +6,6 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU Public License */ -/* Used by quiz navigation links to force a form submit, and hence save the user's data. */ -function navigate(page) { - var ourForm = document.getElementById('responseform'); - ourForm.action = ourForm.action.replace(/page=.*/, 'page=' + page); - if (ourForm.onsubmit) { - ourForm.onsubmit(); - } - ourForm.submit(); -} - /* Use this in an onkeypress handler, to stop enter submitting the forum unless you are actually on the submit button. Don't stop the user typing things in text areas. */ function check_enter(e) { diff --git a/theme/standard/styles_layout.css b/theme/standard/styles_layout.css index 6741f44198..5df23df9e0 100644 --- a/theme/standard/styles_layout.css +++ b/theme/standard/styles_layout.css @@ -2562,7 +2562,6 @@ body.notes .notesgroup { text-align: left; margin: 0 auto 1.8em auto; border: 1px solid; - clear: both; } .que .info { float: left; @@ -3818,14 +3817,21 @@ body#mod-forum-search .introcontent { #passwordform { margin: 1em 0; } -#mod-quiz-attempt #page { +#mod-quiz-attempt #middle-column { text-align: center; } #mod-quiz-attempt .pagingbar { margin: 1.5em auto; } -#mod-quiz-attempt #page { - text-align: center; +#mod-quiz-attempt #middle-column { + margin: 0 0 0 12.5em; +} +#mod-quiz-attempt #left-column { + width: 11.5em; + float: left; +} +#mod-quiz-attempt .submitbtns { + text-align: left; } #mod-quiz-attempt #quiz-timer-outer { @@ -4048,6 +4054,26 @@ table.quizreviewsummary td.cell { text-align: center; margin: 6px 0; } + +#quiznavigation input.qnbutton { + border: 1px solid grey; + background: white; + font-weight: bold; + width: 1.5em; + height: 1.5em; + margin-right: 0.3em; + text-align: middle; +} +#quiznavigation input.qnbutton:hover { + background: silver; +} +#quiznavigation .qn_buttons { + margin: 0.2em; +} +#quiznavigation input.qnbutton.thispage { + background: #eee; +} + /*** *** Modules: Resource ***/ -- 2.39.5