diff --git a/admin/tool/mobile/classes/api.php b/admin/tool/mobile/classes/api.php index 2f1242e4a30..acb31b3e049 100644 --- a/admin/tool/mobile/classes/api.php +++ b/admin/tool/mobile/classes/api.php @@ -127,7 +127,7 @@ class api { 'rememberusername' => $CFG->rememberusername, 'authloginviaemail' => $CFG->authloginviaemail, 'registerauth' => $CFG->registerauth, - 'forgottenpasswordurl' => $CFG->forgottenpasswordurl, + 'forgottenpasswordurl' => clean_param($CFG->forgottenpasswordurl, PARAM_URL), // We may expect a mailto: here. 'authinstructions' => $authinstructions, 'authnoneenabled' => (int) is_enabled_auth('none'), 'enablewebservices' => $CFG->enablewebservices, @@ -204,6 +204,7 @@ class api { } if (empty($section) or $section == 'sitepolicies') { + $settings->sitepolicy = $CFG->sitepolicy; $settings->disableuserimages = $CFG->disableuserimages; } diff --git a/admin/tool/mobile/tests/externallib_test.php b/admin/tool/mobile/tests/externallib_test.php index fbbca7db848..2f565411872 100644 --- a/admin/tool/mobile/tests/externallib_test.php +++ b/admin/tool/mobile/tests/externallib_test.php @@ -94,12 +94,14 @@ class tool_mobile_external_testcase extends externallib_advanced_testcase { set_config('typeoflogin', api::LOGIN_VIA_BROWSER, 'tool_mobile'); set_config('logo', 'mock.png', 'core_admin'); set_config('logocompact', 'mock.png', 'core_admin'); + set_config('forgottenpasswordurl', 'mailto:fake@email.zy'); // Test old hack. list($authinstructions, $notusedformat) = external_format_text($authinstructions, FORMAT_MOODLE, $context->id); $expected['registerauth'] = 'email'; $expected['authinstructions'] = $authinstructions; $expected['typeoflogin'] = api::LOGIN_VIA_BROWSER; $expected['launchurl'] = "$CFG->wwwroot/$CFG->admin/tool/mobile/launch.php"; + $expected['forgottenpasswordurl'] = ''; // Expect empty when it's not an URL. if ($logourl = $OUTPUT->get_logo_url()) { $expected['logourl'] = $logourl->out(false); @@ -121,6 +123,10 @@ class tool_mobile_external_testcase extends externallib_advanced_testcase { require_once($CFG->dirroot . '/course/format/lib.php'); $this->resetAfterTest(true); + + $mysitepolicy = 'http://mysite.is/policy/'; + set_config('sitepolicy', $mysitepolicy); + $result = external::get_config(); $result = external_api::clean_returnvalue(external::get_config_returns(), $result); @@ -141,6 +147,7 @@ class tool_mobile_external_testcase extends externallib_advanced_testcase { array('name' => 'numsections', 'value' => course_get_format($SITE)->get_course()->numsections), array('name' => 'newsitems', 'value' => $SITE->newsitems), array('name' => 'commentsperpage', 'value' => $CFG->commentsperpage), + array('name' => 'sitepolicy', 'value' => $mysitepolicy), array('name' => 'disableuserimages', 'value' => $CFG->disableuserimages), array('name' => 'mygradesurl', 'value' => user_mygrades_url()->out(false)), ); @@ -150,8 +157,7 @@ class tool_mobile_external_testcase extends externallib_advanced_testcase { // Change a value and retrieve filtering by section. set_config('commentsperpage', 1); $expected[10]['value'] = 1; - unset($expected[11]); - unset($expected[12]); + array_splice($expected, 11); $result = external::get_config('frontpagesettings'); $result = external_api::clean_returnvalue(external::get_config_returns(), $result); diff --git a/course/externallib.php b/course/externallib.php index 2006fe75288..50f0429376d 100644 --- a/course/externallib.php +++ b/course/externallib.php @@ -256,8 +256,9 @@ class core_course_external extends external_api { if (!empty($cm->showdescription) or $cm->modname == 'label') { // We want to use the external format. However from reading get_formatted_content(), $cm->content format is always FORMAT_HTML. + $options = array('noclean' => true); list($module['description'], $descriptionformat) = external_format_text($cm->content, - FORMAT_HTML, $modcontext->id, $cm->modname, 'intro', $cm->id); + FORMAT_HTML, $modcontext->id, $cm->modname, 'intro', $cm->id, $options); } //url of the module diff --git a/grade/grading/lib.php b/grade/grading/lib.php index 46fd52a83c0..d7c82946a18 100644 --- a/grade/grading/lib.php +++ b/grade/grading/lib.php @@ -489,7 +489,7 @@ class grading_manager { * Returns the given method's controller in the gradable area * * @param string $method the method name, eg 'rubric' (must be available) - * @return grading_controller + * @return gradingform_controller */ public function get_controller($method) { global $CFG, $DB; @@ -534,7 +534,7 @@ class grading_manager { /** * Returns the controller for the active method if it is available * - * @return null|grading_controller + * @return null|gradingform_controller */ public function get_active_controller() { if ($gradingmethod = $this->get_active_method()) { diff --git a/lib/phpunit/classes/base_testcase.php b/lib/phpunit/classes/base_testcase.php index 231ce1f4198..fcb8786eaa4 100644 --- a/lib/phpunit/classes/base_testcase.php +++ b/lib/phpunit/classes/base_testcase.php @@ -242,7 +242,7 @@ abstract class base_testcase extends PHPUnit_Framework_TestCase { } } // match by exact string else { - if ($node->getAttribute($name) != $value) { + if ($node->getAttribute($name) !== (string) $value) { $invalid = true; } } diff --git a/message/output/popup/templates/message_popover.mustache b/message/output/popup/templates/message_popover.mustache index 666242a875f..03559938f51 100644 --- a/message/output/popup/templates/message_popover.mustache +++ b/message/output/popup/templates/message_popover.mustache @@ -53,33 +53,21 @@ {{$headertext}}{{#str}} messages, message {{/str}}{{/headertext}} {{$headeractions}} - {{< core/hover_tooltip }} - {{$anchor}} - - {{#pix}} t/markasread, core, {{#str}} markallread {{/str}} {{/pix}} - {{> core/loading }} - - {{/anchor}} - {{$tooltip}}{{#str}} markallread {{/str}}{{/tooltip}} - {{/ core/hover_tooltip }} - {{< core/hover_tooltip }} - {{$anchor}} - - {{#pix}} i/settings, core, {{#str}} messagepreferences, message {{/str}} {{/pix}} - - {{/anchor}} - {{$tooltip}}{{#str}} messagepreferences, message {{/str}}{{/tooltip}} - {{/ core/hover_tooltip }} + + {{#pix}} t/markasread, core, {{#str}} markallread {{/str}} {{/pix}} + {{> core/loading }} + + + {{#pix}} i/settings, core, {{#str}} messagepreferences, message {{/str}} {{/pix}} + {{/headeractions}} {{$content}} diff --git a/message/output/popup/templates/notification_popover.mustache b/message/output/popup/templates/notification_popover.mustache index b0684ed3c08..97efbff1638 100644 --- a/message/output/popup/templates/notification_popover.mustache +++ b/message/output/popup/templates/notification_popover.mustache @@ -52,28 +52,18 @@ {{$headertext}}{{#str}} notifications, message {{/str}}{{/headertext}} {{$headeractions}} - {{< core/hover_tooltip }} - {{$anchor}} - - {{#pix}} t/markasread, core, {{#str}} markallread {{/str}} {{/pix}} - {{> core/loading }} - - {{/anchor}} - {{$tooltip}}{{#str}} markallread {{/str}}{{/tooltip}} - {{/ core/hover_tooltip }} - {{< core/hover_tooltip }} - {{$anchor}} - - {{#pix}} i/settings, core, {{#str}} notificationpreferences, message {{/str}} {{/pix}} - - {{/anchor}} - {{$tooltip}}{{#str}} notificationpreferences, message {{/str}}{{/tooltip}} - {{/ core/hover_tooltip }} + + {{#pix}} t/markasread, core, {{#str}} markallread {{/str}} {{/pix}} + {{> core/loading }} + + + {{#pix}} i/settings, core, {{#str}} notificationpreferences, message {{/str}} {{/pix}} + {{/headeractions}} {{$content}} diff --git a/mod/assign/styles.css b/mod/assign/styles.css index 087102ee8d5..11b64bbfa14 100644 --- a/mod/assign/styles.css +++ b/mod/assign/styles.css @@ -1218,3 +1218,10 @@ position: inherit; } /** End of base fixes **/ + +/** Fix to YUI tree (which is a table) when displayed within grading table. **/ +.path-mod-assign table.generaltable table td.ygtvcell { + border: 0; + padding: 0; +} +/** End of YUI tree fix **/ diff --git a/mod/label/mod_form.php b/mod/label/mod_form.php index a892fd2fd00..fec23dfcd57 100644 --- a/mod/label/mod_form.php +++ b/mod/label/mod_form.php @@ -30,6 +30,9 @@ require_once ($CFG->dirroot.'/course/moodleform_mod.php'); class mod_label_mod_form extends moodleform_mod { function definition() { + global $PAGE; + + $PAGE->force_settings_menu(); $mform = $this->_form; diff --git a/mod/quiz/report/attemptsreport.php b/mod/quiz/report/attemptsreport.php index 4545a7099f5..06614ebc858 100644 --- a/mod/quiz/report/attemptsreport.php +++ b/mod/quiz/report/attemptsreport.php @@ -138,6 +138,48 @@ abstract class quiz_attempts_report extends quiz_default_report { return array($currentgroup, $studentsjoins, $groupstudentsjoins, $groupstudentsjoins); } + /** + * Outputs the things you commonly want at the top of a quiz report. + * + * Calls through to {@link print_header_and_tabs()} and then + * outputs the standard group selector, number of attempts summary, + * and messages to cover common cases when the report can't be shown. + * + * @param stdClass $cm the course_module information. + * @param stdClass $course the course settings. + * @param stdClass $quiz the quiz settings. + * @param mod_quiz_attempts_report_options $options the current report settings. + * @param int $currentgroup the current group. + * @param bool $hasquestions whether there are any questions in the quiz. + * @param bool $hasstudents whether there are any relevant students. + */ + protected function print_standard_header_and_messages($cm, $course, $quiz, + $options, $currentgroup, $hasquestions, $hasstudents) { + global $OUTPUT; + + $this->print_header_and_tabs($cm, $course, $quiz, $this->mode); + + if (groups_get_activity_groupmode($cm)) { + // Groups are being used, so output the group selector if we are not downloading. + groups_print_activity_menu($cm, $options->get_url()); + } + + // Print information on the number of existing attempts. + if ($strattemptnum = quiz_num_attempt_summary($quiz, $cm, true, $currentgroup)) { + echo '
' . $strattemptnum . '
'; + } + + if (!$hasquestions) { + echo quiz_no_questions_message($quiz, $cm, $this->context); + } else if ($currentgroup == self::NO_GROUPS_ALLOWED) { + echo $OUTPUT->notification(get_string('notingroup')); + } else if (!$hasstudents) { + echo $OUTPUT->notification(get_string('nostudentsyet')); + } else if ($currentgroup && !$this->hasgroupstudents) { + echo $OUTPUT->notification(get_string('nostudentsingroup')); + } + } + /** * Add all the user-related columns to the $columns and $headers arrays. * @param table_sql $table the table being constructed. diff --git a/mod/quiz/report/overview/report.php b/mod/quiz/report/overview/report.php index d5d47bd07d0..e5c0e932836 100644 --- a/mod/quiz/report/overview/report.php +++ b/mod/quiz/report/overview/report.php @@ -98,36 +98,13 @@ class quiz_overview_report extends quiz_attempts_report { $this->course = $course; // Hack to make this available in process_actions. $this->process_actions($quiz, $cm, $currentgroup, $groupstudentsjoins, $allowedjoins, $options->get_url()); + $hasquestions = quiz_has_questions($quiz->id); + // Start output. if (!$table->is_downloading()) { // Only print headers if not asked to download data. - $this->print_header_and_tabs($cm, $course, $quiz, $this->mode); - } - - if ($groupmode = groups_get_activity_groupmode($cm)) { - // Groups are being used, so output the group selector if we are not downloading. - if (!$table->is_downloading()) { - groups_print_activity_menu($cm, $options->get_url()); - } - } - - // Print information on the number of existing attempts. - if (!$table->is_downloading()) { - // Do not print notices when downloading. - if ($strattemptnum = quiz_num_attempt_summary($quiz, $cm, true, $currentgroup)) { - echo '
' . $strattemptnum . '
'; - } - } - - $hasquestions = quiz_has_questions($quiz->id); - if (!$table->is_downloading()) { - if (!$hasquestions) { - echo quiz_no_questions_message($quiz, $cm, $this->context); - } else if (!$hasstudents) { - echo $OUTPUT->notification(get_string('nostudentsyet')); - } else if ($currentgroup && !$this->hasgroupstudents) { - echo $OUTPUT->notification(get_string('nostudentsingroup')); - } + $this->print_standard_header_and_messages($cm, $course, $quiz, + $options, $currentgroup, $hasquestions, $hasstudents); // Print the display options. $this->form->display(); diff --git a/mod/quiz/report/overview/tests/behat/basic.feature b/mod/quiz/report/overview/tests/behat/basic.feature index a61f2aee781..841d40bf6f3 100644 --- a/mod/quiz/report/overview/tests/behat/basic.feature +++ b/mod/quiz/report/overview/tests/behat/basic.feature @@ -1,4 +1,4 @@ -@mod @mod_quiz +@mod @mod_quiz @quiz @quiz_overview Feature: Basic use of the Grades report In order to easily get an overview of quiz attempts As a teacher diff --git a/mod/quiz/report/responses/first_or_all_responses_table.php b/mod/quiz/report/responses/first_or_all_responses_table.php index 4a90a08e40e..4f2600a13c2 100644 --- a/mod/quiz/report/responses/first_or_all_responses_table.php +++ b/mod/quiz/report/responses/first_or_all_responses_table.php @@ -68,6 +68,15 @@ class quiz_first_or_all_responses_table extends quiz_last_responses_table { // Insert an extra field in attempt data and extra rows where necessary. $newrawdata = array(); foreach ($this->rawdata as $attempt) { + if (!isset($this->questionusagesbyactivity[$attempt->usageid])) { + // This is a user without attempts. + $attempt->try = 0; + $attempt->lasttryforallparts = true; + $newrawdata[] = $attempt; + continue; + } + + // We have an attempt, which may require several rows. $maxtriesinanyslot = 1; foreach ($this->questionusagesbyactivity[$attempt->usageid]->get_slots() as $slot) { $tries = $this->get_no_of_tries($attempt, $slot); @@ -230,7 +239,7 @@ class quiz_first_or_all_responses_table extends quiz_last_responses_table { * @return string What to put in the cell for this column, for this row data. */ public function col_email($tablerow) { - if ($tablerow->try != 1) { + if ($tablerow->try > 1) { return ''; } else { return $tablerow->email; @@ -244,18 +253,27 @@ class quiz_first_or_all_responses_table extends quiz_last_responses_table { * @return string What to put in the cell for this column, for this row data. */ public function col_sumgrades($tablerow) { - if (!$tablerow->lasttryforallparts) { + if ($tablerow->try == 0) { + // We are showing a user without a quiz attempt. + return '-'; + } else if (!$tablerow->lasttryforallparts) { + // There are more rows to come for this quiz attempt, so we will show this later. return ''; } else { + // Last row for this attempt. Now is the time to show attempt-related data. return parent::col_sumgrades($tablerow); } } - public function col_state($tablerow) { - if (!$tablerow->lasttryforallparts) { + if ($tablerow->try == 0) { + // We are showing a user without a quiz attempt. + return '-'; + } else if (!$tablerow->lasttryforallparts) { + // There are more rows to come for this quiz attempt, so we will show this later. return ''; } else { + // Last row for this attempt. Now is the time to show attempt-related data. return parent::col_state($tablerow); } } diff --git a/mod/quiz/report/responses/report.php b/mod/quiz/report/responses/report.php index f72fdbbdfd9..693029eeb6e 100644 --- a/mod/quiz/report/responses/report.php +++ b/mod/quiz/report/responses/report.php @@ -111,36 +111,13 @@ class quiz_responses_report extends quiz_attempts_report { $this->process_actions($quiz, $cm, $currentgroup, $groupstudentsjoins, $allowedjoins, $options->get_url()); + $hasquestions = quiz_has_questions($quiz->id); + // Start output. if (!$table->is_downloading()) { // Only print headers if not asked to download data. - $this->print_header_and_tabs($cm, $course, $quiz, $this->mode); - } - - if ($groupmode = groups_get_activity_groupmode($cm)) { - // Groups are being used, so output the group selector if we are not downloading. - if (!$table->is_downloading()) { - groups_print_activity_menu($cm, $options->get_url()); - } - } - - // Print information on the number of existing attempts. - if (!$table->is_downloading()) { - // Do not print notices when downloading. - if ($strattemptnum = quiz_num_attempt_summary($quiz, $cm, true, $currentgroup)) { - echo '
' . $strattemptnum . '
'; - } - } - - $hasquestions = quiz_has_questions($quiz->id); - if (!$table->is_downloading()) { - if (!$hasquestions) { - echo quiz_no_questions_message($quiz, $cm, $this->context); - } else if (!$hasstudents) { - echo $OUTPUT->notification(get_string('nostudentsyet')); - } else if ($currentgroup && !$this->hasgroupstudents) { - echo $OUTPUT->notification(get_string('nostudentsingroup')); - } + $this->print_standard_header_and_messages($cm, $course, $quiz, + $options, $currentgroup, $hasquestions, $hasstudents); // Print the display options. $this->form->display(); diff --git a/mod/quiz/report/responses/responses_form.php b/mod/quiz/report/responses/responses_form.php index 461dcd2d3e2..4fdbe909a01 100644 --- a/mod/quiz/report/responses/responses_form.php +++ b/mod/quiz/report/responses/responses_form.php @@ -70,6 +70,7 @@ class quiz_responses_settings_form extends mod_quiz_attempts_report_form { question_attempt::ALL_TRIES => get_string('alltries', 'question')) ); $mform->setDefault('whichtries', question_attempt::LAST_TRY); + $mform->disabledIf('whichtries', 'attempts', 'eq', quiz_attempts_report::ENROLLED_WITHOUT); } } } diff --git a/mod/quiz/report/responses/tests/behat/basic.feature b/mod/quiz/report/responses/tests/behat/basic.feature new file mode 100644 index 00000000000..b8344ea20f6 --- /dev/null +++ b/mod/quiz/report/responses/tests/behat/basic.feature @@ -0,0 +1,91 @@ +@mod @mod_quiz @quiz @quiz_reponses +Feature: Basic use of the Responses report + In order to see how my students are progressing + As a teacher + I need to see all their quiz responses + + Background: Using the Responses report + Given the following "users" exist: + | username | firstname | lastname | + | teacher | The | Teacher | + | student1 | Student | One | + | student2 | Student | Two | + And the following "courses" exist: + | fullname | shortname | + | Course 1 | C1 | + And the following "course enrolments" exist: + | user | course | role | + | teacher | C1 | editingteacher | + | student1 | C1 | student | + | student2 | C1 | student | + And the following "question categories" exist: + | contextlevel | reference | name | + | Course | C1 | Test questions | + And the following "activities" exist: + | activity | name | intro | course | idnumber | preferredbehaviour | + | quiz | Quiz 1 | Quiz 1 description | C1 | quiz1 | interactive | + And the following "questions" exist: + | questioncategory | qtype | name | template | + | Test questions | numerical | NQ | pi3tries | + And quiz "Quiz 1" contains the following questions: + | question | page | maxmark | + | NQ | 1 | 3.0 | + + @javascript + Scenario: Report works when there are no attempts + When I log in as "teacher" + And I am on "Course 1" course homepage + And I follow "Quiz 1" + And I navigate to "Results > Responses" in current page administration + Then I should see "Attempts: 0" + And I should see "Nothing to display" + And I set the field "Attempts from" to "enrolled users who have not attempted the quiz" + And I press "Show report" + And "Student One" row "State" column of "responses" table should contain "-" + + @javascript + Scenario: Report works when there are attempts + # Add an attempt + Given I log in as "student1" + And I am on "Course 1" course homepage + And I follow "Quiz 1" + And I press "Attempt quiz now" + And I set the field "Answer" to "1.0" + And I press "Check" + And I press "Try again" + And I set the field "Answer" to "3.0" + And I press "Check" + And I press "Try again" + And I set the field "Answer" to "3.14" + And I press "Check" + And I press "Finish attempt ..." + And I press "Submit all and finish" + And I click on "Submit all and finish" "button" in the "Confirmation" "dialogue" + And I log out + + When I log in as "teacher" + And I am on "Course 1" course homepage + And I follow "Quiz 1" + And I navigate to "Results > Responses" in current page administration + Then I should see "Attempts: 1" + And I should see "Student One" + And I should not see "Student Two" + And I set the field "Attempts from" to "enrolled users who have, or have not, attempted the quiz" + And I set the field "Which tries" to "All tries" + And I press "Show report" + And "Student OneReview attempt" row "Response 1Sort by Response 1 Ascending" column of "responses" table should contain "1.0" + And "Student OneReview attempt" row "State" column of "responses" table should contain "" + And "Finished" row "Grade/100.00Sort by Grade/100.00 Ascending" column of "responses" table should contain "33.33" + And "Finished" row "Response 1Sort by Response 1 Ascending" column of "responses" table should contain "3.14" + And "Student Two" row "State" column of "responses" table should contain "-" + And "Student Two" row "Response 1Sort by Response 1 Ascending" column of "responses" table should contain "-" + + @javascript + Scenario: Report does not allow strange combinations of options + When I log in as "teacher" + And I am on "Course 1" course homepage + And I follow "Quiz 1" + And I navigate to "Results > Responses" in current page administration + And the "Which tries" "select" should be enabled + And I set the field "Attempts from" to "enrolled users who have not attempted the quiz" + Then the "Which tries" "select" should be disabled diff --git a/question/behaviour/manualgraded/tests/walkthrough_test.php b/question/behaviour/manualgraded/tests/walkthrough_test.php index d63030c9248..c47e2053e1b 100644 --- a/question/behaviour/manualgraded/tests/walkthrough_test.php +++ b/question/behaviour/manualgraded/tests/walkthrough_test.php @@ -18,8 +18,7 @@ * This file contains tests that walks a question through the manual graded * behaviour. * - * @package qbehaviour - * @subpackage manualgraded + * @package qbehaviour_manualgraded * @copyright 2009 The Open University * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ @@ -622,4 +621,40 @@ class qbehaviour_manualgraded_walkthrough_testcase extends qbehaviour_walkthroug new question_pattern_expectation($preg) ); } + + public function test_manual_grading_reshows_exactly_the_mark_input() { + global $PAGE; + + // The current text editor depends on the users profile setting - so it needs a valid user. + $this->setAdminUser(); + // Required to init a text editor. + $PAGE->set_url('/'); + + // Create an essay question graded out of 15 and attempt it. + $essay = test_question_maker::make_an_essay_question(); + $this->start_attempt_at_question($essay, 'deferredfeedback', 15); + $this->process_submission(array('answer' => 'This is my wonderful essay!', 'answerformat' => FORMAT_HTML)); + $this->quba->finish_all_questions(); + + // Verify. + $this->check_current_state(question_state::$needsgrading); + $this->check_current_mark(null); + $this->assertEquals('This is my wonderful essay!', + $this->quba->get_response_summary($this->slot)); + + // Try to process a grade where the score will be stored rounded. + $this->manual_grade('Comment', '5.0', FORMAT_HTML); + + // Verify. + $this->check_current_state(question_state::$mangrpartial); + $this->check_current_mark(5); + $this->displayoptions->manualcomment = question_display_options::EDITABLE; + $this->render(); + $this->check_output_contains_text_input('-mark', '5.0'); + + // Rescale what the question is worth, and verify the display. + $this->get_question_attempt()->set_max_mark(1); + $this->render(); + $this->check_output_contains_text_input('-mark', '0.3333333'); + } } diff --git a/question/behaviour/rendererbase.php b/question/behaviour/rendererbase.php index ea6a1878afe..b47488726e5 100644 --- a/question/behaviour/rendererbase.php +++ b/question/behaviour/rendererbase.php @@ -126,9 +126,6 @@ abstract class qbehaviour_renderer extends plugin_renderer_base { if (!is_null($currentmark)) { $attributes['value'] = $currentmark; } - $a = new stdClass(); - $a->max = $qa->format_max_mark($options->markdp); - $a->mark = html_writer::empty_tag('input', $attributes); $markrange = html_writer::empty_tag('input', array( 'type' => 'hidden', @@ -152,6 +149,9 @@ abstract class qbehaviour_renderer extends plugin_renderer_base { array('class' => 'error')) . html_writer::empty_tag('br'); } + $a = new stdClass(); + $a->max = $qa->format_max_mark($options->markdp); + $a->mark = html_writer::empty_tag('input', $attributes); $mark = html_writer::tag('div', html_writer::tag('div', html_writer::tag('label', get_string('mark', 'question'), array('for' => $markfield)), diff --git a/question/engine/datalib.php b/question/engine/datalib.php index e486e4699ee..0ef5816aba6 100644 --- a/question/engine/datalib.php +++ b/question/engine/datalib.php @@ -525,15 +525,11 @@ ORDER BY qas.sequencenumber ", $qubaids->usage_id_in_params()); - if (!$records->valid()) { - throw new coding_exception('Failed to load questions_usages_by_activity for qubaid_condition :' . $qubaids); - } - $qubas = array(); - do { + while ($records->valid()) { $record = $records->current(); $qubas[$record->qubaid] = question_usage_by_activity::load_from_records($records, $record->qubaid); - } while ($records->valid()); + } $records->close(); diff --git a/question/engine/questionattempt.php b/question/engine/questionattempt.php index fa110dde2ae..d295170e3d3 100644 --- a/question/engine/questionattempt.php +++ b/question/engine/questionattempt.php @@ -649,17 +649,29 @@ class question_attempt { /** * This is used by the manual grading code, particularly in association with - * validation. If there is a mark submitted in the request, then use that, - * otherwise use the latest mark for this question. - * @return number the current manual mark for this question, formatted for display. + * validation. It gets the current manual mark for a question, in exactly the string + * form that the teacher entered it, if possible. This may come from the current + * POST request, if there is one, otherwise from the database. + * + * @return string the current manual mark for this question, in the format the teacher typed, + * if possible. */ public function get_current_manual_mark() { + // Is there a current value in the current POST data? If so, use that. $mark = $this->get_submitted_var($this->get_behaviour_field_name('mark'), PARAM_RAW_TRIMMED); - if (is_null($mark)) { - return format_float($this->get_mark(), 7, true, true); - } else { + if ($mark !== null) { return $mark; } + + // Otherwise, use the stored value. + // If the question max mark has not changed, use the stored value that was input. + $storedmaxmark = $this->get_last_behaviour_var('maxmark'); + if ($storedmaxmark !== null && ($storedmaxmark - $this->get_max_mark()) < 0.0000005) { + return $this->get_last_behaviour_var('mark'); + } + + // The max mark for this question has changed so we must re-scale the current mark. + return format_float($this->get_mark(), 7, true, true); } /** diff --git a/question/type/numerical/tests/helper.php b/question/type/numerical/tests/helper.php index 7157dfb3460..650674b423c 100644 --- a/question/type/numerical/tests/helper.php +++ b/question/type/numerical/tests/helper.php @@ -35,7 +35,7 @@ defined('MOODLE_INTERNAL') || die(); */ class qtype_numerical_test_helper extends question_test_helper { public function get_test_questions() { - return array('pi', 'unit', 'currency'); + return array('pi', 'unit', 'currency', 'pi3tries'); } /** @@ -71,6 +71,15 @@ class qtype_numerical_test_helper extends question_test_helper { return $num; } + /** + * Get the form data that corresponds to saving a numerical question. + * + * This question asks for Pi to two decimal places. It has feedback + * for various wrong responses. There is hint data there, but + * it is all blank, so no hints are created if this question is saved. + * + * @return stdClass simulated question form data. + */ public function get_numerical_question_form_data_pi() { $form = new stdClass(); $form->name = 'Pi to two d.p.'; @@ -156,6 +165,22 @@ class qtype_numerical_test_helper extends question_test_helper { return $form; } + /** + * Get the form data that corresponds to saving a numerical question. + * + * Like {@link get_numerical_question_form_data_pi()}, but + * this time with two hints, making this suitable for use + * with the Interactive with multiple tries behaviour. + * + * @return stdClass simulated question form data. + */ + public function get_numerical_question_form_data_pi3tries() { + $form = $this->get_numerical_question_form_data_pi(); + $form->hint[0]['text'] = 'First hint'; + $form->hint[1]['text'] = 'Second hint'; + return $form; + } + public function get_numerical_question_data_pi() { $q = new stdClass(); $q->name = 'Pi to two d.p.'; diff --git a/search/engine/solr/lang/en/search_solr.php b/search/engine/solr/lang/en/search_solr.php index b8d7e12b3f5..6addfea4c24 100644 --- a/search/engine/solr/lang/en/search_solr.php +++ b/search/engine/solr/lang/en/search_solr.php @@ -28,7 +28,8 @@ $string['errorcreatingschema'] = 'Error creating the Solr schema: {$a}'; $string['errorvalidatingschema'] = 'Error validating Solr schema: field {$a->fieldname} does not exist. Please follow this link to set up the required fields.'; $string['extensionerror'] = 'The Apache Solr PHP extension is not installed. Please check the documentation.'; $string['fileindexing'] = 'Enable file indexing'; -$string['fileindexing_help'] = 'If your Solr install supports it, this feature allows Moodle to send files to be indexed.'; +$string['fileindexing_help'] = 'If your Solr install supports it, this feature allows Moodle to send files to be indexed.
+You will need to reindex all site contents after enabling this option for all files to be added.'; $string['fileindexsettings'] = 'File indexing settings'; $string['maxindexfilekb'] = 'Maximum file size to index (kB)'; $string['maxindexfilekb_help'] = 'Files larger than this number of kilobytes will not be included in search indexing. If set to zero, files of any size will be indexed.'; diff --git a/theme/boost/scss/moodle/course.scss b/theme/boost/scss/moodle/course.scss index 8a1475cc1f8..d4f04d9ef6f 100644 --- a/theme/boost/scss/moodle/course.scss +++ b/theme/boost/scss/moodle/course.scss @@ -538,13 +538,20 @@ span.editinstructions { } .dndupload-progress-outer { - @extend progress; + background-color: $progress-bg; + @include border-radius($progress-border-radius); + @include box-shadow($progress-box-shadow); + display: block; + width: 100%; + height: $spacer-y; + margin-bottom: $spacer-y; } .dndupload-progress-inner { - .progress { - @extend .progress-bar; - } + background-color: $progress-bar-color; + @include border-left-radius($progress-border-radius); + display: inline-block; + height: $spacer-y; } .dndupload-hidden { diff --git a/theme/boost/scss/moodle/question.scss b/theme/boost/scss/moodle/question.scss index c306f044440..e92f97a6bf7 100644 --- a/theme/boost/scss/moodle/question.scss +++ b/theme/boost/scss/moodle/question.scss @@ -304,6 +304,14 @@ body.path-question-type { vertical-align: baseline; } +.que.multianswer .formulation .yui3-widget-positioned { + box-sizing: content-box; + .feedbackspan { + width: inherit; + max-width: inherit; + } +} + .path-mod-quiz input[size] { width: auto; max-width: 100%; diff --git a/theme/bootstrapbase/less/moodle/question.less b/theme/bootstrapbase/less/moodle/question.less index afbcdfd644b..a6bb21cf8a3 100644 --- a/theme/bootstrapbase/less/moodle/question.less +++ b/theme/bootstrapbase/less/moodle/question.less @@ -237,6 +237,12 @@ body.path-question-type .fitem_fgroup .accesshide { width: auto; vertical-align: baseline; } +.que.multianswer .formulation .yui3-widget-positioned .feedbackspan { + box-sizing: content-box; + padding-bottom: 0; + max-width: inherit; + width: inherit; +} .path-mod-quiz input[size] { width: auto; } diff --git a/theme/bootstrapbase/style/moodle.css b/theme/bootstrapbase/style/moodle.css index 60db968ead7..77fc4f353be 100644 --- a/theme/bootstrapbase/style/moodle.css +++ b/theme/bootstrapbase/style/moodle.css @@ -6962,6 +6962,12 @@ body.path-question-type .fitem_fgroup .accesshide { width: auto; vertical-align: baseline; } +.que.multianswer .formulation .yui3-widget-positioned .feedbackspan { + box-sizing: content-box; + padding-bottom: 0; + max-width: inherit; + width: inherit; +} .path-mod-quiz input[size] { width: auto; } diff --git a/version.php b/version.php index a75b9317283..2c6fd424b09 100644 --- a/version.php +++ b/version.php @@ -29,11 +29,11 @@ defined('MOODLE_INTERNAL') || die(); -$version = 2016120505.10; // YYYYMMDD = weekly release date of this DEV branch. +$version = 2016120505.11; // YYYYMMDD = weekly release date of this DEV branch. // RR = release increments - 00 in DEV branches. // .XX = incremental changes. -$release = '3.2.5+ (Build: 20171025)'; // Human-friendly version name +$release = '3.2.5+ (Build: 20171027)'; // Human-friendly version name $branch = '32'; // This version's branch. $maturity = MATURITY_STABLE; // This version's maturity level.