From: tjhunt Date: Thu, 23 Jul 2009 09:20:33 +0000 (+0000) Subject: quiz: MDL-19891 fix that quiz navigation block that was broken by the blocks changes. X-Git-Url: http://git.mjollnir.org/gw?a=commitdiff_plain;h=d18675a8d797c370eb7b2164d9922b6c25f606e1;p=moodle.git quiz: MDL-19891 fix that quiz navigation block that was broken by the blocks changes. Sadly it now requries JavaScript again, at least for best operation. --- diff --git a/lang/en_utf8/quiz.php b/lang/en_utf8/quiz.php index 0f9127ceeb..3bb53d50e3 100644 --- a/lang/en_utf8/quiz.php +++ b/lang/en_utf8/quiz.php @@ -434,6 +434,7 @@ $string['multichoice'] = 'Multiple Choice'; $string['multipleanswers'] = 'Choose at least one answer.'; $string['multiplier'] = 'Multiplier'; $string['name'] = 'Name'; +$string['navnojswarning'] = 'Warning: these links will not save your answers. Use the next button at the bottom of the page.'; $string['neverallononepage'] = 'Never, all questions on one page'; $string['newattemptfail'] = 'Error: Could not start a new attempt at the quiz'; $string['newpage'] = 'New page'; @@ -675,6 +676,7 @@ $string['showbreaks'] = 'Show page breaks'; $string['showcategorycontents'] = 'Show category contents $a->arrow'; $string['showcorrectanswer'] = 'In feedback, show correct answers?'; $string['showdetailedmarks'] = 'Show mark details'; +$string['showeachpage'] = 'Show one page at a time'; $string['showfeedback'] = 'After answering, show feedback?'; $string['showhidden'] = 'Also show old questions'; $string['showinsecurepopup'] = 'Use a \'secure\' popup window for attempts'; diff --git a/mod/quiz/attempt.php b/mod/quiz/attempt.php index e3aa0e1540..e19792c0fc 100644 --- a/mod/quiz/attempt.php +++ b/mod/quiz/attempt.php @@ -86,7 +86,6 @@ $PAGE->blocks->add_pretend_block($navbc, $firstregion); // Print the page header - $PAGE->requires->yui_lib('event'); $title = get_string('attempt', 'quiz', $attemptobj->get_attempt_number()); $headtags = $attemptobj->get_html_head_contributions($page); if ($accessmanager->securewindow_required($attemptobj->is_preview_user())) { @@ -123,9 +122,7 @@ // A quiz page with a lot of questions can take a long time to load, and we // want the protection afforded by init_quiz_form immediately, so include the // JS now. - echo $PAGE->requires->yui_lib('event')->asap(); - echo $PAGE->requires->js('mod/quiz/quiz.js')->asap(); - echo $PAGE->requires->js_function_call('init_quiz_form')->asap(); + echo $PAGE->requires->js_function_call('init_quiz_form')->now(); echo '
'; /// Print all the questions @@ -137,17 +134,15 @@ echo '
'; if ($attemptobj->is_last_page($page)) { $nextpage = -1; - $nextpageforie = 'gotosummary'; } else { $nextpage = $page + 1; - $nextpageforie = 'gotopage' . $nextpage; } - echo ''; + echo ''; echo "
"; // Some hidden fields to trach what is going on. echo ''; - echo ''; + echo ''; echo ''; echo ''; diff --git a/mod/quiz/attemptlib.php b/mod/quiz/attemptlib.php index ac81a76a83..fc099ac211 100644 --- a/mod/quiz/attemptlib.php +++ b/mod/quiz/attemptlib.php @@ -1,19 +1,39 @@ . + /** - * This class handles loading all the information about a quiz attempt into memory, - * and making it available for attemtp.php, summary.php and review.php. - * Initially, it only loads a minimal amout of information about each attempt - loading - * extra information only when necessary or when asked. The class tracks which questions - * are loaded. - *//** */ + * Back-end code for handling data about quizzes and the current user's attempt. + * + * There are classes for loading all the information about a quiz and attempts, + * and for displaying the navigation panel. + * + * @package quiz + * @copyright 2008 onwards Tim Hunt + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ -if (!defined('MOODLE_INTERNAL')) { - die('Direct access to this script is forbidden.'); /// It must be included from a Moodle page. -} /** * Class for quiz exceptions. Just saves a couple of arguments on the * constructor for a moodle_exception. + * + * @copyright 2008 Tim Hunt + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since Moodle 2.0 */ class moodle_quiz_exception extends moodle_exception { function __construct($quizobj, $errorcode, $a = NULL, $link = '', $debuginfo = null) { @@ -25,8 +45,16 @@ class moodle_quiz_exception extends moodle_exception { } /** - * A base class for holding and accessing information about a quiz and its questions, - * before details of a particular attempt are loaded. + * A class encapsulating a quiz and the questions it contains, and making the + * information available to scripts like view.php. + * + * Initially, it only loads a minimal amout of information about each question - loading + * extra information only when necessary or when asked. The class tracks which questions + * are loaded. + * + * @copyright 2008 Tim Hunt + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since Moodle 2.0 */ class quiz { // Fields initialised in the constructor. @@ -63,10 +91,19 @@ class quiz { } // Functions for loading more data ===================================================== + /** + * Convenience method. Calls {@link load_questions()} with the list of + * question ids for a given page. + * + * @param integer $page a page number. + */ public function load_questions_on_page($page) { $this->load_questions($this->pagequestionids[$page]); } + /** + * Load just basic information about all the questions in this quiz. + */ public function preload_questions() { if (empty($this->questionids)) { throw new moodle_quiz_exception($this, 'noquestions', $this->edit_url()); @@ -79,7 +116,7 @@ class quiz { } /** - * Load some or all of the questions for this quiz. + * Fully load some or all of the questions for this quiz. You must call {@link preload_questions()} first. * * @param array $questionids question ids of the questions to load. null for all. */ @@ -301,14 +338,20 @@ class quiz { } // Private methods ===================================================================== - // Check that the definition of a particular question is loaded, and if not throw an exception. + /** + * Check that the definition of a particular question is loaded, and if not throw an exception. + * @param $id a questionid. + */ protected function ensure_question_loaded($id) { if (isset($this->questions[$id]->_partiallyloaded)) { throw new moodle_quiz_exception($this, 'questionnotloaded', $id); } } - private function determine_layout() { + /** + * Populate {@link $questionids} and {@link $pagequestionids} from the layout. + */ + protected function determine_layout() { $this->questionids = array(); $this->pagequestionids = array(); @@ -340,7 +383,9 @@ class quiz { } } - // Number the questions. + /** + * Number the questions, adding a _number field to each one. + */ private function number_questions() { $number = 1; foreach ($this->pagequestionids as $page => $questionids) { @@ -368,6 +413,10 @@ class quiz { /** * This class extends the quiz class to hold data about the state of a particular attempt, * in addition to the data about the quiz. + * + * @copyright 2008 Tim Hunt + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since Moodle 2.0 */ class quiz_attempt extends quiz { // Fields initialised in the constructor. @@ -424,7 +473,12 @@ class quiz_attempt extends quiz { } } - + /** + * Load basic information about the state of each question. + * + * This is enough to, for example, show the state of each question in the + * navigation panel, but only takes one DB query. + */ public function preload_question_states() { if (empty($this->questionids)) { throw new moodle_quiz_exception($this, 'noquestions', $this->edit_url()); @@ -435,6 +489,14 @@ class quiz_attempt extends quiz { } } + /** + * Load a particular state of a particular question. Used by the reviewquestion.php + * script to let the teacher walk through the entire sequence of a student's + * interaction with a question. + * + * @param $questionid the question id + * @param $stateid the id of the particular state to load. + */ public function load_specific_question_state($questionid, $stateid) { global $DB; $state = question_load_specific_state($this->questions[$questionid], @@ -508,6 +570,12 @@ class quiz_attempt extends quiz { } } + /** + * Get the current state of a question in the attempt. + * + * @param $questionid a questionid. + * @return object the state. + */ public function get_question_state($questionid) { $this->ensure_state_loaded($questionid); return $this->states[$questionid]; @@ -612,16 +680,16 @@ class quiz_attempt extends quiz { // URLs related to this attempt ======================================================== /** - * @param integer $page if specified, the URL of this particular page of the attempt, otherwise - * the URL will go to the first page. * @param integer $questionid a question id. If set, will add a fragment to the URL * to jump to a particuar question on the page. + * @param integer $page if specified, the URL of this particular page of the attempt, otherwise + * the URL will go to the first page. If -1, deduce $page from $questionid. + * @param integer $thispage if not -1, the current page. Will cause links to other things on + * this page to be output as only a fragment. * @return string the URL to continue this attempt. */ - public function attempt_url($questionid = 0, $page = -1) { - global $CFG; - return $CFG->wwwroot . '/mod/quiz/attempt.php?attempt=' . $this->attempt->id . - $this->page_and_question_fragment($questionid, $page); + public function attempt_url($questionid = 0, $page = -1, $thispage = -1) { + return $this->page_and_question_url('attempt', $questionid, $page, false, $thispage); } /** @@ -641,32 +709,46 @@ class quiz_attempt extends quiz { } /** + * @param integer $questionid a question id. If set, will add a fragment to the URL + * to jump to a particuar question on the page. If -1, deduce $page from $questionid. * @param integer $page if specified, the URL of this particular page of the attempt, otherwise * the URL will go to the first page. - * @param integer $questionid a question id. If set, will add a fragment to the URL - * to jump to a particuar question on the page. * @param boolean $showall if true, the URL will be to review the entire attempt on one page, * and $page will be ignored. - * @param $otherattemptid if given, link to another attempt, instead of the one we represent. + * @param integer $thispage if not -1, the current page. Will cause links to other things on + * this page to be output as only a fragment. * @return string the URL to review this attempt. */ - public function review_url($questionid = 0, $page = -1, $showall = false) { - global $CFG; - return $CFG->wwwroot . '/mod/quiz/review.php?attempt=' . $this->attempt->id . - $this->page_and_question_fragment($questionid, $page, $showall); + public function review_url($questionid = 0, $page = -1, $showall = false, $thispage = -1) { + return $this->page_and_question_url('review', $questionid, $page, $showall, $thispage); } // Bits of content ===================================================================== + /** + * Initialise the JS etc. required all the questions on a page.. + * @param mixed $page a page number, or 'all'. + */ public function get_html_head_contributions($page = 'all') { - return get_html_head_contributions($this->get_question_ids($page), - $this->questions, $this->states); + global $PAGE; + // The JS does important things like navigation and so must be initialised + // as seen as possible, particularly if the page is loading slowly. + $PAGE->requires->yui_lib('dom')->in_head(); + $PAGE->requires->yui_lib('event')->in_head(); + $PAGE->requires->js('mod/quiz/quiz.js')->in_head(); + get_html_head_contributions($this->get_question_ids($page), $this->questions, $this->states); } + /** + * Initialise the JS etc. required by one question. + * @param integer $questionid the question id. + */ public function get_question_html_head_contributions($questionid) { - return get_html_head_contributions(array($questionid), - $this->questions, $this->states); + get_html_head_contributions(array($questionid), $this->questions, $this->states); } + /** + * Print the HTML for the start new preview button. + */ public function print_restart_preview_button() { global $CFG; echo '
'; @@ -675,6 +757,10 @@ class quiz_attempt extends quiz { echo '
'; } + /** + * Return the HTML of the quiz timer. + * @return string HTML content. + */ public function get_timer_html() { return '
' . get_string('timeleft', 'quiz') . '
'; @@ -702,17 +788,34 @@ class quiz_attempt extends quiz { $this->quiz, $options); } + /** + * Triggers the sending of the notification emails at the end of this attempt. + */ public function quiz_send_notification_emails() { quiz_send_notification_emails($this->course, $this->quiz, $this->attempt, $this->context, $this->cm); } - public function get_navigation_panel($panelclass, $page) { - $panel = new $panelclass($this, $this->get_review_options(), $page); + /** + * Get the navigation panel object for this attempt. + * + * @param $panelclass The type of panel, quiz_attempt_nav_panel or quiz_review_nav_panel + * @param $page the current page number. + * @param $showall whether we are showing the whole quiz on one page. (Used by review.php) + * @return quiz_nav_panel_base the requested object. + */ + public function get_navigation_panel($panelclass, $page, $showall = false) { + $panel = new $panelclass($this, $this->get_review_options(), $page, $showall); return $panel->get_contents(); } - /// List of all this user's attempts for people who can see reports. + /** + * Given a URL containing attempt={this attempt id}, return an array of variant URLs + * @param $url a URL. + * @return string HTML fragment. Comma-separated list of links to the other + * attempts with the attempt number as the link text. The curent attempt is + * included but is not a link. + */ public function links_to_other_attempts($url) { $search = '/\battempt=' . $this->attempt->id . '\b/'; $attempts = quiz_get_user_attempts($this->quiz->id, $this->attempt->userid, 'all'); @@ -732,10 +835,19 @@ class quiz_attempt extends quiz { } // Methods for processing manual comments ============================================== - // I am not sure it is a good idea to have update methods here - this class is only - // about getting data out of the question engine, and helping to display it, apart from - // this. + /** + * Process a manual comment for a question in this attempt. + * @param $questionid + * @param integer $questionid the question id + * @param string $comment the new comment from the teacher. + * @param mixed $grade the grade the teacher assigned, or '' to not change the grade. + * @return mixed true on success, a string error message if a problem is detected + * (for example score out of range). + */ public function process_comment($questionid, $comment, $grade) { + // I am not sure it is a good idea to have update methods here - this + // class is only about getting data out of the question engine, and + // helping to display it, apart from this. $this->ensure_question_loaded($questionid); $this->ensure_state_loaded($questionid); $state = $this->states[$questionid]; @@ -755,6 +867,11 @@ class quiz_attempt extends quiz { return $error; } + /** + * Print the fields of the comment form for questions in this attempt. + * @param $questionid a question id. + * @param $prefix Prefix to add to all field names. + */ public function question_print_comment_fields($questionid, $prefix) { global $DB; @@ -772,7 +889,10 @@ class quiz_attempt extends quiz { } // Private methods ===================================================================== - // Check that the state of a particular question is loaded, and if not throw an exception. + /** + * Check that the state of a particular question is loaded, and if not throw an exception. + * @param integer $id a question id. + */ private function ensure_state_loaded($id) { if (!array_key_exists($id, $this->states) || isset($this->states[$id]->_partiallyloaded)) { throw new moodle_quiz_exception($this, 'statenotloaded', $id); @@ -788,16 +908,23 @@ class quiz_attempt extends quiz { } /** - * Enter description here... + * Get a URL for a particular question on a particular page of the quiz. + * Used by {@link attempt_url()} and {@link review_url()}. * - * @param unknown_type $questionid the id of a particular question on the page to jump to. - * @param integer $page -1 to look up the page number from the questionid, otherwise the page number to use. - * @param boolean $showall - * @return string bit to add to the end of a URL. + * @param string $script. Used in the URL like /mod/quiz/$script.php + * @param integer $questionid the id of a particular question on the page to jump to. 0 to just use the $page parameter. + * @param integer $page -1 to look up the page number from the questionid, otherwise the page number to go to. + * @param boolean $showall if true, return a URL with showall=1, and not page number + * @param integer $thispage the page we are currently on. Links to questoins on this + * page will just be a fragment #q123. -1 to disable this. + * @return The requested URL. */ - private function page_and_question_fragment($questionid, $page, $showall = false) { + protected function page_and_question_url($script, $questionid, $page, $showall, $thispage) { + global $CFG; + + // Fix up $page if ($page == -1) { - if ($questionid) { + if ($questionid && !$showall) { $page = $this->questions[$questionid]->_page; } else { $page = 0; @@ -806,28 +933,40 @@ class quiz_attempt extends quiz { if ($showall) { $page = 0; } - $fragment = ''; + + // Work out the correct start to the URL. + if ($thispage == $page) { + $url = ''; + } else { + $url = $CFG->wwwroot . '/mod/quiz/' . $script . '.php?attempt=' . $this->attempt->id; + if ($showall) { + $url .= '&showall=1'; + } else if ($page > 0) { + $url .= '&page=' . $page; + } + } + + // Add a fragment to scroll down ot the question. if ($questionid) { if ($questionid == reset($this->pagequestionids[$page])) { // First question on page, go to top. - $fragment = '#'; + $url .= '#'; } else { - $fragment = '#q' . $questionid; + $url .= '#q' . $questionid; } } - $param = ''; - if ($showall) { - $param = '&showall=1'; - } else if ($page > 0) { - $param = '&page=' . $page; - } - return $param . $fragment; + + return $url; } } /** * A PHP Iterator for conviniently looping over the questions in a quiz. The keys are the question * numbers (with 'i' for descriptions) and the values are the question objects. + * + * @copyright 2008 Tim Hunt + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since Moodle 2.0 */ class quiz_attempt_question_iterator implements Iterator { private $attemptobj; // Reference to the quiz_attempt object we provide access to. @@ -882,38 +1021,52 @@ class quiz_attempt_question_iterator implements Iterator { } } +/** + * Represents the navigation panel, and builds a {@link block_contents} to allow + * it to be output. + * + * @copyright 2008 Tim Hunt + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since Moodle 2.0 + */ abstract class quiz_nav_panel_base { protected $attemptobj; protected $options; protected $page; + protected $showall; - protected function __construct(quiz_attempt $attemptobj, $options, $page) { + public function __construct(quiz_attempt $attemptobj, $options, $page, $showall) { $this->attemptobj = $attemptobj; $this->options = $options; $this->page = $page; + $this->showall = $showall; } protected function get_question_buttons() { - global $PAGE; $html = '
' . "\n"; foreach ($this->attemptobj->get_question_iterator() as $number => $question) { $html .= $this->get_question_button($number, $question) . "\n"; - $PAGE->requires->js_function_call('quiz_init_nav_button', - array($this->get_button_id($question), $question->id)); } $html .= "
\n"; return $html; } - protected function get_button_id($question) { - // The id to put on the button element in the HTML. - return 'quiznavbutton' . $question->id; + protected function get_question_button($number, $question) { + $strstate = get_string($this->attemptobj->get_question_status($question->id), 'quiz'); + return '' . + $number . ' (' . $strstate . ')'; } - abstract protected function get_question_button($number, $question); + protected function get_before_button_bits() { + return ''; + } abstract protected function get_end_bits(); + abstract protected function get_question_url($question); + protected function get_user_picture() { global $DB; $user = $DB->get_record('user', array('id' => $this->attemptobj->get_userid())); @@ -930,7 +1083,7 @@ abstract class quiz_nav_panel_base { $classes = $this->attemptobj->get_question_status($question->id); // Plus a marker for the current page. - if ($question->_page == $this->page) { + if ($this->showall || $question->_page == $this->page) { $classes .= ' thispage'; } @@ -942,10 +1095,14 @@ abstract class quiz_nav_panel_base { } public function get_contents() { + global $PAGE; + $PAGE->requires->js_function_call('quiz_init_nav_flags'); + $content = ''; if ($this->attemptobj->get_quiz()->showuserpicture) { $content .= $this->get_user_picture() . "\n"; } + $content .= $this->get_before_button_bits(); $content .= $this->get_question_buttons() . "\n"; $content .= '
' . "\n" . $this->get_end_bits() . "\n
\n"; @@ -957,49 +1114,54 @@ abstract class quiz_nav_panel_base { } } +/** + * Specialisation of {@link quiz_nav_panel_base} for the attempt quiz page. + * + * @copyright 2008 Tim Hunt + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since Moodle 2.0 + */ 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_url($question) { + return $this->attemptobj->attempt_url($question->id, -1, $this->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_before_button_bits() { + return '
' . get_string('navnojswarning', 'quiz') . "
\n"; } protected function get_end_bits() { + global $PAGE; $output = ''; - $output .= ''; + $output .= '' . get_string('endtest', 'quiz') . ''; $output .= $this->attemptobj->get_timer_html(); + $output .= $PAGE->requires->js_function_call('quiz_init_attempt_nav')->now(); return $output; } } +/** + * Specialisation of {@link quiz_nav_panel_base} for the review quiz page. + * + * @copyright 2008 Tim Hunt + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since Moodle 2.0 + */ 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) { - $strstate = get_string($this->attemptobj->get_question_status($question->id), 'quiz'); - return '' . $number . '(' . $strstate . ''; + protected function get_question_url($question) { + return $this->attemptobj->review_url($question->id, -1, $this->showall, $this->page); } protected function get_end_bits() { + $html = ''; + if ($this->attemptobj->get_num_pages() > 1) { + if ($this->showall) { + $html = '' . get_string('showeachpage', 'quiz') . ''; + } else { + $html = '' . get_string('showall', 'quiz') . ''; + } + } $accessmanager = $this->attemptobj->get_access_manager(time()); - $html = '' . - get_string('showall', 'quiz') . ''; $html .= $accessmanager->print_finish_review_link($this->attemptobj->is_preview_user(), true); return $html; } diff --git a/mod/quiz/processattempt.php b/mod/quiz/processattempt.php index afd5df4028..cbabdc5094 100644 --- a/mod/quiz/processattempt.php +++ b/mod/quiz/processattempt.php @@ -29,23 +29,6 @@ $timeup = optional_param('timeup', 0, PARAM_BOOL); // True if form was submitted $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)) { - $nextpage = -1; -} else { - $numpagesinquiz = $attemptobj->get_num_pages(); - for ($i = 0; $i < $numpagesinquiz; $i++) { - if (optional_param('gotopage' . $i, false, PARAM_BOOL)) { - $nextpage = $i; - break; - } - } -} - /// Set $nexturl now. It will be updated if a particular question was sumbitted in /// adaptive mode. if ($nextpage == -1) { @@ -163,8 +146,9 @@ if (!$finishattempt) { /// We have been asked to finish attempt, so do that ////////////////////// -/// Load the states of questions we have not done anything with, and reload the -/// ones we changed above. +/// Now load the state of every question, reloading the ones we messed around +/// with above. +$attemptobj->preload_question_states(); $attemptobj->load_question_states(); /// Move each question to the closed state. diff --git a/mod/quiz/quiz.js b/mod/quiz/quiz.js index 97cf4eeb68..4d312baa11 100644 --- a/mod/quiz/quiz.js +++ b/mod/quiz/quiz.js @@ -148,11 +148,54 @@ quiz_timer = { } }; -// Initialise a button on the navigation panel. -function quiz_init_nav_button(buttonid, questionid) { - // Arrange to be notified if the flagged state changes. - var button = document.getElementById(buttonid); - button.stateupdater = new quiz_nav_updater(button, questionid); +// Set up synchronisation between question flags and the corresponding button in the nav panel. +function quiz_init_nav_flags() { + var navblock = document.getElementById('quiznavigation'); + var buttons = YAHOO.util.Dom.getElementsByClassName('qnbutton', 'a', navblock); + for (var i = 0; i < buttons.length; i++) { + var button = buttons[i]; + var questionid = button.id.match(/\d+/)[0]; + button.stateupdater = new quiz_nav_updater(button, questionid); + } +} + +// Make the links in the attempt nav panel submit the form. +function quiz_init_attempt_nav() { + var warning = document.getElementById('quiznojswarning'); + warning.parentNode.removeChild(warning); + var navblock = document.getElementById('quiznavigation'); + var buttons = YAHOO.util.Dom.getElementsByClassName('qnbutton', 'a', navblock); + for (var i = 0; i < buttons.length; i++) { + var button = buttons[i]; + if (YAHOO.util.Dom.hasClass(button, 'thispage')) { + continue; + } + var pageidmatch = button.href.match(/page=(\d+)/); + var nav = {pageid: pageidmatch[1]}; + var questionidmatch = button.href.match(/#q(\d+)/); + if (questionidmatch) { + nav.questionid = questionidmatch[1]; + } + YAHOO.util.Event.addListener(button, 'click', quiz_nav_button_click, nav); + } + var endlink = YAHOO.util.Dom.getElementsByClassName('endtestlink', 'a', navblock)[0]; + YAHOO.util.Event.addListener(endlink, 'click', quiz_end_test_click); +} + +function quiz_nav_button_click(e, nav) { + YAHOO.util.Event.preventDefault(e); + document.getElementById('nextpagehiddeninput').value = nav.pageid; + var form = document.getElementById('responseform'); + if (nav.questionid) { + form.action += '#q' + nav.questionid; + } + form.submit(); +} + +function quiz_end_test_click(e) { + YAHOO.util.Event.preventDefault(e); + document.getElementById('nextpagehiddeninput').value = -1; + document.getElementById('responseform').submit(); } function quiz_nav_updater(element, questionid) { diff --git a/mod/quiz/review.php b/mod/quiz/review.php index 9ffe1c4ea7..9a55256ca2 100644 --- a/mod/quiz/review.php +++ b/mod/quiz/review.php @@ -72,12 +72,11 @@ } /// Arrange for the navigation to be displayed. - $navbc = $attemptobj->get_navigation_panel('quiz_review_nav_panel', $page); + $navbc = $attemptobj->get_navigation_panel('quiz_review_nav_panel', $page, $showall); $firstregion = reset($PAGE->blocks->get_regions()); $PAGE->blocks->add_pretend_block($navbc, $firstregion); /// Print the page header - $PAGE->requires->js('mod/quiz/quiz.js'); $headtags = $attemptobj->get_html_head_contributions($page); if ($accessmanager->securewindow_required($attemptobj->is_preview_user())) { $accessmanager->setup_secure_page($attemptobj->get_course()->shortname.': '.format_string($attemptobj->get_quiz_name()), $headtags); @@ -236,7 +235,7 @@ if ($lastpage) { $accessmanager->print_finish_review_link($attemptobj->is_preview_user()); } else { - link_arrow_right(get_string('next'), s($attemptobj->review_url(0, $page + 1))); + echo link_arrow_right(get_string('next'), s($attemptobj->review_url(0, $page + 1))); } echo "
"; diff --git a/mod/quiz/summary.php b/mod/quiz/summary.php index d834aaf991..6ecc0a56ff 100644 --- a/mod/quiz/summary.php +++ b/mod/quiz/summary.php @@ -68,7 +68,7 @@ if ($attemptobj->is_preview_user()) { print_heading($title); /// Prepare the summary table header -$table->class = 'generaltable quizsummaryofattempt'; +$table->class = 'generaltable quizsummaryofattempt boxaligncenter'; $table->head = array(get_string('question', 'quiz'), get_string('status', 'quiz')); $table->align = array('left', 'left'); $table->size = array('', ''); diff --git a/theme/standard/styles_color.css b/theme/standard/styles_color.css index a12bb92f03..6acbb00c74 100644 --- a/theme/standard/styles_color.css +++ b/theme/standard/styles_color.css @@ -1174,7 +1174,9 @@ table.quizreviewsummary td.cell { #quiznavigation .qnbutton.incorrect { background-color: #fcc; } - +#quiznojswarning { + color: red; +} #mod-quiz-report .dubious{ background-color: #fcc; } diff --git a/theme/standard/styles_layout.css b/theme/standard/styles_layout.css index a4b46e5e9a..2edc42babd 100644 --- a/theme/standard/styles_layout.css +++ b/theme/standard/styles_layout.css @@ -4377,8 +4377,12 @@ body.jsenabled .jshidewhenenabled { height: 16px; vertical-align: middle; } -#mod-quiz-attempt #quiz-timer { - display: none; +#mod-quiz-attempt #quiz-timer, +#mod-quiz-summary #quiz-timer { + display: none; /* Revealed by JavaScript if applicable */ +} +#mod-quiz-summary #quiz-timer { + margin-top: 1em; } #mod-quiz-attempt #quiz-time-left { font-weight: bold; @@ -4612,13 +4616,20 @@ table.quizreviewsummary td.cell { float: left; } #quiznavigation .othernav { - clear: both; + clear: both; } #quiznavigation .othernav a, #quiznavigation .othernav input { display: block; margin: 0.5em 0; } +#quiznojswarning { + font-size: 0.7em; + line-height: 1.1; +} +.jsenabled #quiznojswarning { + display: none; +} .mod-quiz div.tabtree a span img.iconsmall { vertical-align: baseline; }