diff --git a/mod/quiz/accessmanager.php b/mod/quiz/accessmanager.php index 7a833a96ba2..81208fb6e2e 100644 --- a/mod/quiz/accessmanager.php +++ b/mod/quiz/accessmanager.php @@ -368,9 +368,16 @@ class quiz_access_manager { * @return mod_quiz_preflight_check_form the form. */ public function get_preflight_check_form(moodle_url $url, $attemptid) { + // This form normally wants POST submissins. However, it also needs to + // accept GET submissions. Since formslib is strict, we have to detect + // which case we are in, and set the form property appropriately. + $method = 'post'; + if (!empty($_GET['_qf__mod_quiz_preflight_check_form'])) { + $method = 'get'; + } return new mod_quiz_preflight_check_form($url->out_omit_querystring(), array('rules' => $this->rules, 'quizobj' => $this->quizobj, - 'attemptid' => $attemptid, 'hidden' => $url->params())); + 'attemptid' => $attemptid, 'hidden' => $url->params()), $method); } /** diff --git a/mod/quiz/accessmanager_form.php b/mod/quiz/accessmanager_form.php index cf7855dcdc4..41f29afefac 100644 --- a/mod/quiz/accessmanager_form.php +++ b/mod/quiz/accessmanager_form.php @@ -38,6 +38,7 @@ class mod_quiz_preflight_check_form extends moodleform { protected function definition() { $mform = $this->_form; + $this->_form->updateAttributes(array('id' => 'mod_quiz_preflight_form')); foreach ($this->_customdata['hidden'] as $name => $value) { if ($name === 'sesskey') { @@ -54,7 +55,8 @@ class mod_quiz_preflight_check_form extends moodleform { } } - $this->add_action_buttons(true, get_string('continue')); + $this->add_action_buttons(true, get_string('startattempt', 'quiz')); + $mform->setDisableShortforms(); } public function validation($data, $files) { diff --git a/mod/quiz/accessrule/timelimit/lang/en/quizaccess_timelimit.php b/mod/quiz/accessrule/timelimit/lang/en/quizaccess_timelimit.php index f0bee8bff4c..106dfe9ee9d 100644 --- a/mod/quiz/accessrule/timelimit/lang/en/quizaccess_timelimit.php +++ b/mod/quiz/accessrule/timelimit/lang/en/quizaccess_timelimit.php @@ -27,5 +27,7 @@ defined('MOODLE_INTERNAL') || die(); +$string['confirmstartheader'] = 'Timed quiz'; +$string['confirmstart'] = 'The quiz has a time limit of {$a}. Time will count down from the moment you start your attempt and you must submit before it expires. Are you sure that you wish to start now?'; $string['pluginname'] = 'Time limit quiz access rule'; $string['quiztimelimit'] = 'Time limit: {$a}'; diff --git a/mod/quiz/accessrule/timelimit/rule.php b/mod/quiz/accessrule/timelimit/rule.php index 59558408be9..879b4a6da21 100644 --- a/mod/quiz/accessrule/timelimit/rule.php +++ b/mod/quiz/accessrule/timelimit/rule.php @@ -63,6 +63,18 @@ class quizaccess_timelimit extends quiz_access_rule_base { return false; } return $endtime - $timenow; + } + public function is_preflight_check_required($attemptid) { + // Warning only required if the attempt is not already started. + return $attemptid === null; + } + + public function add_preflight_check_form_fields(mod_quiz_preflight_check_form $quizform, + MoodleQuickForm $mform, $attemptid) { + $mform->addElement('header', 'honestycheckheader', + get_string('confirmstartheader', 'quizaccess_timelimit')); + $mform->addElement('static', 'honestycheckmessage', '', + get_string('confirmstart', 'quizaccess_timelimit', format_time($this->quiz->timelimit))); } } diff --git a/mod/quiz/amd/build/preflightcheck.min.js b/mod/quiz/amd/build/preflightcheck.min.js new file mode 100644 index 00000000000..48befcfa765 --- /dev/null +++ b/mod/quiz/amd/build/preflightcheck.min.js @@ -0,0 +1 @@ +define(["jquery","core/yui"],function(a,b){var c={confirmDialogue:null,init:function(a,d,e,f){var g=a;b.use("moodle-core-notification","moodle-core-formchangechecker","io-form",function(){b.one(e)&&(c.confirmDialogue=new M.core.dialogue({headerContent:d,bodyContent:b.one(e),draggable:!0,visible:!1,center:!0,modal:!0,width:null,extraClasses:["mod_quiz_preflight_popup"]}),b.one(a).on("click",c.displayDialogue),b.one("#id_cancel").on("click",c.hideDialogue),g=c.confirmDialogue.get("boundingBox").one('[name="submitbutton"]')),f&&b.one(g).on("click",c.launchQuizPopup,c,f)})},displayDialogue:function(a){a&&a.halt(),c.confirmDialogue.show()},hideDialogue:function(a){a&&a.halt(),c.confirmDialogue.hide(a)},launchQuizPopup:function(a,c){a.halt(),M.core_formchangechecker.reset_form_dirty_state();var d=a.target.ancestor("form");window.openpopup(a,{url:d.get("action")+"?"+b.IO.stringify(d).replace(/\bcancel=/,"x="),windowname:"quizpopup",options:c,fullscreen:!0})}};return c}); \ No newline at end of file diff --git a/mod/quiz/amd/src/preflightcheck.js b/mod/quiz/amd/src/preflightcheck.js new file mode 100644 index 00000000000..e9c9e17bbea --- /dev/null +++ b/mod/quiz/amd/src/preflightcheck.js @@ -0,0 +1,112 @@ +// This file is part of Moodle - http://moodle.org/ +// +// Moodle is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Moodle is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Moodle. If not, see . + +/** + * This class manages the confirmation pop-up (also called the pre-flight check) + * that is sometimes shown when a use clicks the start attempt button. + * + * This is also responsible for opening the pop-up window, if the quiz requires to be in one. + * + * @module mod_quiz/preflightcheck + * @class preflightcheck + * @package mod_quiz + * @copyright 2016 The Open University + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since 3.1 + */ +define(['jquery', 'core/yui'], function($, Y) { + + /** + * @alias module:mod_quiz/preflightcheck + */ + var t = { + confirmDialogue: null, + + /** + * Initialise the start attempt button. + * + * @param {String} startButtonId the id of the start attempt button that we will be enhancing. + * @param {String} confirmationTitle the title of the dialogue. + * @param {String} confirmationForm selector for the confirmation form to show in the dialogue. + * @param {String} popupoptions If not null, the quiz should be launced in a pop-up. + */ + init: function(startButton, confirmationTitle, confirmationForm, popupoptions) { + var finalStartButton = startButton; + + Y.use('moodle-core-notification', 'moodle-core-formchangechecker', 'io-form', function () { + if (Y.one(confirmationForm)) { + t.confirmDialogue = new M.core.dialogue({ + headerContent: confirmationTitle, + bodyContent: Y.one(confirmationForm), + draggable: true, + visible: false, + center: true, + modal: true, + width: null, + extraClasses: ['mod_quiz_preflight_popup'] + }); + + Y.one(startButton).on('click', t.displayDialogue); + Y.one('#id_cancel').on('click', t.hideDialogue); + + finalStartButton = t.confirmDialogue.get('boundingBox').one('[name="submitbutton"]'); + } + + if (popupoptions) { + Y.one(finalStartButton).on('click', t.launchQuizPopup, t, popupoptions); + } + }); + }, + + /** + * Display the dialogue. + * @param {Y.EventFacade} e the event being responded to, if any. + */ + displayDialogue: function(e) { + if (e) { + e.halt(); + } + t.confirmDialogue.show(); + }, + + /** + * Hide the dialogue. + * @param {Y.EventFacade} e the event being responded to, if any. + */ + hideDialogue: function(e) { + if (e) { + e.halt(); + } + t.confirmDialogue.hide(e); + }, + + /** + * Event handler for the quiz start attempt button. + */ + launchQuizPopup: function(e, popupoptions) { + e.halt(); + M.core_formchangechecker.reset_form_dirty_state(); + var form = e.target.ancestor('form'); + window.openpopup(e, { + url: form.get('action') + '?' + Y.IO.stringify(form).replace(/\bcancel=/, 'x='), + windowname: 'quizpopup', + options: popupoptions, + fullscreen: true, + }); + } + }; + + return t; +}); diff --git a/mod/quiz/attemptlib.php b/mod/quiz/attemptlib.php index 22819860871..ed1e9c59a6a 100644 --- a/mod/quiz/attemptlib.php +++ b/mod/quiz/attemptlib.php @@ -371,23 +371,13 @@ class quiz { // Bits of content ========================================================= /** - * @param bool $unfinished whether there is currently an unfinished attempt active. - * @return string if the quiz policies merit it, return a warning string to - * be displayed in a javascript alert on the start attempt button. + * @param bool $notused not used. + * @return string an empty string. + * @deprecated since 3.1. This sort of functionality is now entirely handled by quiz access rules. */ - public function confirm_start_attempt_message($unfinished) { - if ($unfinished) { - return ''; - } - - if ($this->quiz->timelimit && $this->quiz->attempts) { - return get_string('confirmstartattempttimelimit', 'quiz', $this->quiz->attempts); - } else if ($this->quiz->timelimit) { - return get_string('confirmstarttimelimit', 'quiz'); - } else if ($this->quiz->attempts) { - return get_string('confirmstartattemptlimit', 'quiz', $this->quiz->attempts); - } - + public function confirm_start_attempt_message($notused) { + debugging('confirm_start_attempt_message is deprecated. ' . + 'This sort of functionality is now entirely handled by quiz access rules.'); return ''; } diff --git a/mod/quiz/lang/en/quiz.php b/mod/quiz/lang/en/quiz.php index a7a643e7472..ca75002ed95 100644 --- a/mod/quiz/lang/en/quiz.php +++ b/mod/quiz/lang/en/quiz.php @@ -202,9 +202,6 @@ $string['confirmclose'] = 'Once you submit, you will no longer be able to change $string['confirmremovequestion'] = 'Are you sure you want to remove this {$a} question?'; $string['confirmremovesectionheading'] = 'Are you sure you want to remove the \'{$a}\' section heading?'; $string['confirmserverdelete'] = 'Are you sure you want to remove the server {$a} from the list?'; -$string['confirmstartattemptlimit'] = 'Number of attempts allowed: {$a}. You are about to start a new attempt. Do you wish to proceed?'; -$string['confirmstartattempttimelimit'] = 'This quiz has a time limit and is limited to {$a} attempt(s). You are about to start a new attempt. Do you wish to proceed?'; -$string['confirmstarttimelimit'] = 'The quiz has a time limit. Are you sure that you wish to start?'; $string['connectionok'] = 'Network connection restored. You may continue safely.'; $string['connectionerror'] = 'Network connection lost. (Autosave failed). diff --git a/mod/quiz/module.js b/mod/quiz/module.js index aafb48c4789..aaa39264513 100644 --- a/mod/quiz/module.js +++ b/mod/quiz/module.js @@ -272,23 +272,6 @@ M.mod_quiz.secure_window = { e.halt(); }, - /** - * Event handler for the quiz start attempt button. - */ - start_attempt_action: function(e, args) { - if (args.startattemptwarning == '') { - openpopup(e, args); - } else { - M.util.show_confirm_dialog(e, { - message: args.startattemptwarning, - callback: function() { - openpopup(e, args); - }, - continuelabel: M.util.get_string('startattempt', 'quiz') - }); - } - }, - init_close_button: function(Y, url) { Y.on('click', function(e) { M.mod_quiz.secure_window.close(url, 0) diff --git a/mod/quiz/renderer.php b/mod/quiz/renderer.php index 8f5d13fc388..855a7e9882e 100644 --- a/mod/quiz/renderer.php +++ b/mod/quiz/renderer.php @@ -422,9 +422,7 @@ class mod_quiz_renderer extends plugin_renderer_base { $output .= $this->heading(format_string($quizobj->get_quiz_name(), true, array("context" => $quizobj->get_context()))); $output .= $this->quiz_intro($quizobj->get_quiz(), $quizobj->get_cm()); - ob_start(); - $mform->display(); - $output .= ob_get_clean(); + $output .= $mform->render(); $output .= $this->footer(); return $output; } @@ -798,9 +796,8 @@ class mod_quiz_renderer extends plugin_renderer_base { if ($viewobj->buttontext) { $output .= $this->start_attempt_button($viewobj->buttontext, - $viewobj->startattempturl, $viewobj->startattemptwarning, + $viewobj->startattempturl, $viewobj->preflightcheckform, $viewobj->popuprequired, $viewobj->popupoptions); - } if ($viewobj->showbacktocourse) { @@ -815,43 +812,44 @@ class mod_quiz_renderer extends plugin_renderer_base { /** * Generates the view attempt button * - * @param int $course The course ID - * @param array $quiz Array containging quiz date - * @param int $cm The Course Module ID - * @param int $context The page Context ID - * @param mod_quiz_view_object $viewobj - * @param string $buttontext + * @param string $buttontext the label to display on the button. + * @param moodle_url $url The URL to POST to in order to start the attempt. + * @param mod_quiz_preflight_check_form $preflightcheckform deprecated. + * @param bool $popuprequired whether the attempt needs to be opened in a pop-up. + * @param array $popupoptions the options to use if we are opening a popup. + * @return string HTML fragment. */ public function start_attempt_button($buttontext, moodle_url $url, - $startattemptwarning, $popuprequired, $popupoptions) { + mod_quiz_preflight_check_form $preflightcheckform = null, + $popuprequired = false, $popupoptions = null) { + + if (is_string($preflightcheckform)) { + // Calling code was not updated since the API change. + debugging('The third argument to start_attempt_button should now be the ' . + 'mod_quiz_preflight_check_form from ' . + 'quiz_access_manager::get_preflight_check_form, not a warning message string.'); + } $button = new single_button($url, $buttontext); $button->class .= ' quizstartbuttondiv'; - $warning = ''; - if ($popuprequired) { - $this->page->requires->js_module(quiz_get_js_module()); - $this->page->requires->js('/mod/quiz/module.js'); - $popupaction = new popup_action('click', $url, 'quizpopup', $popupoptions); - - $button->class .= ' quizsecuremoderequired'; - $button->add_action(new component_action('click', - 'M.mod_quiz.secure_window.start_attempt_action', array( - 'url' => $url->out(false), - 'windowname' => 'quizpopup', - 'options' => $popupaction->get_js_options(), - 'fullscreen' => true, - 'startattemptwarning' => $startattemptwarning, - ))); - - $warning = html_writer::tag('noscript', $this->heading(get_string('noscript', 'quiz'))); - - } else if ($startattemptwarning) { - $button->add_action(new confirm_action($startattemptwarning, null, - get_string('startattempt', 'quiz'))); + $popupjsoptions = null; + if ($popuprequired && $popupoptions) { + $action = new popup_action('click', $url, 'popup', $popupoptions); + $popupjsoptions = $action->get_js_options(); } - return $this->render($button) . $warning; + if ($preflightcheckform) { + $checkform = $preflightcheckform->render(); + } else { + $checkform = null; + } + + $this->page->requires->js_call_amd('mod_quiz/preflightcheck', 'init', + array('.quizstartbuttondiv input[type=submit]', get_string('startattempt', 'quiz'), + '#mod_quiz_preflight_form', $popupjsoptions)); + + return $this->render($button) . $checkform; } /** @@ -1316,10 +1314,11 @@ class mod_quiz_view_object { /** @var string $buttontext caption for the start attempt button. If this is null, show no * button, or if it is '' show a back to the course button. */ public $buttontext; - /** @var string $startattemptwarning alert to show the user before starting an attempt. */ - public $startattemptwarning; /** @var moodle_url $startattempturl URL to start an attempt. */ public $startattempturl; + /** @var moodleform|null $preflightcheckform confirmation form that must be + * submitted before an attempt is started, if required. */ + public $preflightcheckform; /** @var moodle_url $startattempturl URL for any Back to the course button. */ public $backtocourseurl; /** @var bool $showbacktocourse should we show a back to the course button? */ @@ -1330,4 +1329,16 @@ class mod_quiz_view_object { public $popupoptions; /** @var bool $quizhasquestions whether the quiz has any questions. */ public $quizhasquestions; + + public function __get($field) { + switch ($field) { + case 'startattemptwarning': + debugging('startattemptwarning has been deprecated. It is now always blank.'); + return ''; + + default: + debugging('Unknown property ' . $field); + return null; + } + } } diff --git a/mod/quiz/startattempt.php b/mod/quiz/startattempt.php index ae60ae6e308..9b625ec7c0f 100644 --- a/mod/quiz/startattempt.php +++ b/mod/quiz/startattempt.php @@ -125,8 +125,8 @@ if ($lastattempt && ($lastattempt->state == quiz_attempt::IN_PROGRESS || } // Check access. -$output = $PAGE->get_renderer('mod_quiz'); if (!$quizobj->is_preview_user() && $messages) { + $output = $PAGE->get_renderer('mod_quiz'); print_error('attempterror', 'quiz', $quizobj->view_url(), $output->access_messages($messages)); } @@ -137,7 +137,7 @@ if ($accessmanager->is_preflight_check_required($currentattemptid)) { $quizobj->start_attempt_url($page), $currentattemptid); if ($mform->is_cancelled()) { - $accessmanager->back_to_view_page($output); + $accessmanager->back_to_view_page($PAGE->get_renderer('mod_quiz')); } else if (!$mform->get_data()) { @@ -145,6 +145,7 @@ if ($accessmanager->is_preflight_check_required($currentattemptid)) { $PAGE->set_url($quizobj->start_attempt_url($page)); $PAGE->set_title($quizobj->get_quiz_name()); $accessmanager->setup_attempt_page($PAGE); + $output = $PAGE->get_renderer('mod_quiz'); if (empty($quizobj->get_quiz()->showblocks)) { $PAGE->blocks->show_only_fake_blocks(); } diff --git a/mod/quiz/styles.css b/mod/quiz/styles.css index 05188e6d08a..f98ea29a29f 100644 --- a/mod/quiz/styles.css +++ b/mod/quiz/styles.css @@ -345,6 +345,47 @@ table.quizattemptsummary .noreviewmessage { .jsenabled .quizstartbuttondiv.quizsecuremoderequired input { display: inline; } +.quizattempt #mod_quiz_preflight_form { + display: none; +} + +#mod_quiz_preflight_form .femptylabel .fitemtitle { + display: none; +} +#mod_quiz_preflight_form .femptylabel .felement { + margin: 0; + padding: 0; +} + +.moodle-dialogue-base .moodle-dialogue.mod_quiz_preflight_popup { + width: 600px; +} +.moodle-dialogue-base .moodle-dialogue.mod_quiz_preflight_popup .moodle-dialogue-wrap { + overflow: hidden; +} +.moodle-dialogue-base .moodle-dialogue.mod_quiz_preflight_popup .moodle-dialogue-bd { + padding: 0; +} +.moodle-dialogue-base .moodle-dialogue.mod_quiz_preflight_popup .moodle-dialogue-bd #mod_quiz_preflight_form legend { + padding: 0 10px; + margin: 0; + border: 0 none; +} +.moodle-dialogue-base .moodle-dialogue.mod_quiz_preflight_popup .moodle-dialogue-bd #mod_quiz_preflight_form .fitem { + margin-left: 10px; +} +.moodle-dialogue-base .moodle-dialogue.mod_quiz_preflight_popup .moodle-dialogue-bd #mod_quiz_preflight_form #fgroup_id_buttonar { + padding: 10px 0 0; + margin: 0; +} +.moodle-dialogue-base .moodle-dialogue.mod_quiz_preflight_popup .moodle-dialogue-content .moodle-dialogue-ft { + margin: 0; +} +/* Standard Moodle rule that needs to be more specific here. */ +.moodle-dialogue-bd #mod_quiz_preflight_form fieldset.hidden { + display: inherit; + visibility: inherit; +} body.path-mod-quiz .gradedattempt, body.path-mod-quiz table tbody tr.gradedattempt > td { diff --git a/mod/quiz/tests/behat/attempt_begin.feature b/mod/quiz/tests/behat/attempt_begin.feature new file mode 100644 index 00000000000..a2987a8eacc --- /dev/null +++ b/mod/quiz/tests/behat/attempt_begin.feature @@ -0,0 +1,115 @@ +@mod @mod_quiz +Feature: The various checks that may happen when an attept is started + As a student + In order to start a quiz with confidence + I need to be waned if there is a time limit, or various similar things + + Background: + Given the following "users" exist: + | username | firstname | lastname | email | + | student | Student | One | student@example.com | + And the following "courses" exist: + | fullname | shortname | category | + | Course 1 | C1 | 0 | + And the following "course enrolments" exist: + | user | course | role | + | student | C1 | student | + And the following "question categories" exist: + | contextlevel | reference | name | + | Course | C1 | Test questions | + And the following "questions" exist: + | questioncategory | qtype | name | questiontext | + | Test questions | truefalse | TF1 | Text of the first question | + + @javascript + Scenario: Start a quiz with no time limit + Given the following "activities" exist: + | activity | name | intro | course | idnumber | + | quiz | Quiz 1 | Quiz 1 description | C1 | quiz1 | + And quiz "Quiz 1" contains the following questions: + | question | page | + | TF1 | 1 | + When I log in as "student" + And I follow "Course 1" + And I follow "Quiz 1" + And I press "Attempt quiz now" + Then I should see "Text of the first question" + + @javascript + Scenario: Start a quiz with time limit and password + Given the following "activities" exist: + | activity | name | intro | course | idnumber | timelimit | quizpassword | + | quiz | Quiz 1 | Quiz 1 description | C1 | quiz1 | 3600 | Frog | + And quiz "Quiz 1" contains the following questions: + | question | page | + | TF1 | 1 | + When I log in as "student" + And I follow "Course 1" + And I follow "Quiz 1" + And I press "Attempt quiz now" + Then I should see "To attempt this quiz you need to know the quiz password" in the "Start attempt" "dialogue" + And I should see "The quiz has a time limit of 1 hour. Time will " in the "Start attempt" "dialogue" + And I set the field "Quiz password" to "Frog" + And I click on "Start attempt" "button" in the "Start attempt" "dialogue" + And I should see "Text of the first question" + + @javascript + Scenario: Cancel starting a quiz with time limit and password + Given the following "activities" exist: + | activity | name | intro | course | idnumber | timelimit | quizpassword | + | quiz | Quiz 1 | Quiz 1 description | C1 | quiz1 | 3600 | Frog | + And quiz "Quiz 1" contains the following questions: + | question | page | + | TF1 | 1 | + When I log in as "student" + And I follow "Course 1" + And I follow "Quiz 1" + And I press "Attempt quiz now" + And I click on "Cancel" "button" in the "Start attempt" "dialogue" + Then I should see "Quiz 1 description" + And "Attempt quiz now" "button" should be visible + + @javascript + Scenario: Start a quiz with time limit and password, get the password wrong first time + Given the following "activities" exist: + | activity | name | intro | course | idnumber | timelimit | quizpassword | + | quiz | Quiz 1 | Quiz 1 description | C1 | quiz1 | 3600 | Frog | + And quiz "Quiz 1" contains the following questions: + | question | page | + | TF1 | 1 | + When I log in as "student" + And I follow "Course 1" + And I follow "Quiz 1" + And I press "Attempt quiz now" + And I set the field "Quiz password" to "Toad" + And I click on "Start attempt" "button" in the "Start attempt" "dialogue" + Then I should see "Quiz 1 description" + And I should see "To attempt this quiz you need to know the quiz password" + And I should see "The quiz has a time limit of 1 hour. Time will " + And I should see "The password entered was incorrect" + And I set the field "Quiz password" to "Frog" + And I press "Start attempt" + And I should see "Text of the first question" + + @javascript + Scenario: Start a quiz with time limit and password, get the password wrong first time then cancel + Given the following "activities" exist: + | activity | name | intro | course | idnumber | timelimit | quizpassword | + | quiz | Quiz 1 | Quiz 1 description | C1 | quiz1 | 3600 | Frog | + And quiz "Quiz 1" contains the following questions: + | question | page | + | TF1 | 1 | + When I log in as "student" + And I follow "Course 1" + And I follow "Quiz 1" + And I press "Attempt quiz now" + And I set the field "Quiz password" to "Toad" + And I click on "Start attempt" "button" in the "Start attempt" "dialogue" + And I should see "Quiz 1 description" + And I should see "To attempt this quiz you need to know the quiz password" + And I should see "The quiz has a time limit of 1 hour. Time will " + And I should see "The password entered was incorrect" + And I set the field "Quiz password" to "Frog" + And I press "Cancel" + Then I should see "Quiz 1 description" + And "Attempt quiz now" "button" should be visible diff --git a/mod/quiz/upgrade.txt b/mod/quiz/upgrade.txt index 78bee87a9d0..d3828d1afc7 100644 --- a/mod/quiz/upgrade.txt +++ b/mod/quiz/upgrade.txt @@ -1,9 +1,18 @@ This files describes API changes in the quiz code. === 3.1 === + * quiz_attempt::question_print_comment_fields() has been removed. It was broken since at least Moodle 2.0. +* quiz::confirm_start_attempt_message and mod_quiz_view_object::$startattemptwarning + have been deprecated. This functionality is now entirely handled within the + quiz access rule plugins. + +* The third argument to mod_quiz_renderer::start_attempt_button has been changed + from a warning string to a mod_quiz_preflight_check_form. + + === 2.9 === * There have been changes in classes/output/edit_renderer.php for MDL-40990. @@ -100,6 +109,7 @@ This files describes API changes in the quiz code. trigger the event outside this function. Note that the appropriate start event is fired automatically by the quiz_attempt_save_started function. + === 2.7 === * The old quiz.questions database column (comma-separated list of question ids) @@ -130,6 +140,7 @@ This files describes API changes in the quiz code. quiz_delete_empty_page: has had its arguments changed to $quiz and $pagenumber. quiz_has_question_use: now takes $quiz and $slot, not $questionid. + === 2.6 === * As part of improving the page usability and accessibility, we updated the diff --git a/mod/quiz/view.php b/mod/quiz/view.php index 9cf69d052ee..db0c149b050 100644 --- a/mod/quiz/view.php +++ b/mod/quiz/view.php @@ -93,6 +93,7 @@ $viewobj->canreviewmine = $canreviewmine; $attempts = quiz_get_user_attempts($quiz->id, $USER->id, 'finished', true); $lastfinishedattempt = end($attempts); $unfinished = false; +$unfinishedattemptid = null; if ($unfinishedattempt = quiz_get_user_attempt_unfinished($quiz->id, $USER->id)) { $attempts[] = $unfinishedattempt; @@ -105,6 +106,7 @@ if ($unfinishedattempt = quiz_get_user_attempt_unfinished($quiz->id, $USER->id)) if (!$unfinished) { $lastfinishedattempt = $unfinishedattempt; } + $unfinishedattemptid = $unfinishedattempt->id; $unfinishedattempt = null; // To make it clear we do not use this again. } $numattempts = count($attempts); @@ -177,7 +179,11 @@ $viewobj->canedit = has_capability('mod/quiz:manage', $context); $viewobj->editurl = new moodle_url('/mod/quiz/edit.php', array('cmid' => $cm->id)); $viewobj->backtocourseurl = new moodle_url('/course/view.php', array('id' => $course->id)); $viewobj->startattempturl = $quizobj->start_attempt_url(); -$viewobj->startattemptwarning = $quizobj->confirm_start_attempt_message($unfinished); + +if ($accessmanager->is_preflight_check_required($unfinishedattemptid)) { + $viewobj->preflightcheckform = $accessmanager->get_preflight_check_form( + $viewobj->startattempturl, $unfinishedattemptid); +} $viewobj->popuprequired = $accessmanager->attempt_must_be_in_popup(); $viewobj->popupoptions = $accessmanager->get_popup_options();