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();