From 9d7c1d93a0ee0dda7176adab551a56c06ec66d56 Mon Sep 17 00:00:00 2001 From: Nathan Nguyen Date: Mon, 1 Jul 2024 14:15:34 +1000 Subject: [PATCH] MDL-82131 core_grades: penalty indicator --- grade/classes/output/penalty_indicator.php | 90 +++++++++++++++++++ grade/renderer.php | 12 +++ grade/templates/penalty_indicator.mustache | 43 +++++++++ grade/tests/output/penalty_indicator_test.php | 90 +++++++++++++++++++ lang/en/grades.php | 1 + 5 files changed, 236 insertions(+) create mode 100644 grade/classes/output/penalty_indicator.php create mode 100644 grade/templates/penalty_indicator.mustache create mode 100644 grade/tests/output/penalty_indicator_test.php diff --git a/grade/classes/output/penalty_indicator.php b/grade/classes/output/penalty_indicator.php new file mode 100644 index 0000000000000..967108d0490fc --- /dev/null +++ b/grade/classes/output/penalty_indicator.php @@ -0,0 +1,90 @@ +. + +namespace core_grades\output; + +use core\output\renderer_base; +use templatable; +use renderable; + +/** + * The base class for the action bar in the gradebook pages. + * + * @package core_grades + * @copyright 2024 Catalyst IT Australia Pty Ltd + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class penalty_indicator implements templatable, renderable { + /** @var int $decimals the decimal places */ + protected int $decimals; + + /** @var float $penalty the deducted grade */ + protected float $penalty; + + /** @var float|null $finalgrade the final grade */ + protected ?float $finalgrade; + + /** @var float|null $maxgrade the maximum grade */ + protected ?float $maxgrade; + + /** @var array|null $icon icon data */ + protected ?array $icon; + + /** + * The class constructor. + * + * @param int $decimals the decimal places + * @param float $penalty the deducted grade + * @param float|null $finalgrade the final grade + * @param float|null $maxgrade the maximum grade + * @param array|null $icon icon data + */ + public function __construct(int $decimals, float $penalty, ?float $finalgrade = null, + ?float $maxgrade = null, ?array $icon = null) { + $this->icon = $icon; + $this->decimals = $decimals; + $this->penalty = $penalty; + $this->finalgrade = $finalgrade; + $this->maxgrade = $maxgrade; + } + + /** + * Returns the template for the actions bar. + * + * @return string + */ + public function get_template(): string { + return 'core_grades/penalty_indicator'; + } + + /** + * Export the data for the mustache template. + * + * @param \renderer_base $output renderer to be used to render the penalty indicator. + * @return array + */ + public function export_for_template(renderer_base $output) { + $context = [ + 'penalty' => format_float($this->penalty, $this->decimals), + 'finalgrade' => $this->finalgrade ? format_float($this->finalgrade, $this->decimals) : null, + 'maxgrade' => $this->maxgrade ? format_float($this->maxgrade, $this->decimals) : null, + 'icon' => $this->icon ?: ['name' => 'i/risk_xss', 'component' => 'core'] , + 'info' => get_string('gradepenalty_indicator_info', 'core_grades', format_float($this->penalty, $this->decimals)), + ]; + + return $context; + } +} diff --git a/grade/renderer.php b/grade/renderer.php index d3f772d7f7bba..afdf7653ece53 100644 --- a/grade/renderer.php +++ b/grade/renderer.php @@ -18,6 +18,7 @@ use core\output\comboboxsearch; use \core_grades\output\action_bar; +use core_grades\output\penalty_indicator; use core_message\helper; use core_message\api; @@ -227,4 +228,15 @@ public function user_heading(stdClass $user, int $courseid, bool $showbuttons = return $this->render_from_template('core_grades/user_heading', $headingdata); } + + /** + * Renders the penalty indicator. + * + * @param penalty_indicator $penaltyindicator + * @return string The HTML output + */ + public function render_penalty_indicator(penalty_indicator $penaltyindicator): string { + $data = $penaltyindicator->export_for_template($this); + return $this->render_from_template($penaltyindicator->get_template(), $data); + } } diff --git a/grade/templates/penalty_indicator.mustache b/grade/templates/penalty_indicator.mustache new file mode 100644 index 0000000000000..ac109e494e7d0 --- /dev/null +++ b/grade/templates/penalty_indicator.mustache @@ -0,0 +1,43 @@ +{{! + 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 . +}} +{{! + @template core_grades/penalty_indicator + + This template is used to render the penalty indicator. + + + Example context (json): + { + "penalty": 20, + "finalgrade": 50, + "maxgrade": 100, + "info": "Late penalty applied -20 marks" + } +}} + +{{#icon}} + + {{#pix}}{{name}}, {{component}}{{/pix}} + +{{/icon}} +{{#finalgrade}} + + {{#maxgrade}} + {{finalgrade}} / {{maxgrade}} + {{/maxgrade}} + {{^maxgrade}} + {{finalgrade}} + {{/maxgrade}} + +{{/finalgrade}} diff --git a/grade/tests/output/penalty_indicator_test.php b/grade/tests/output/penalty_indicator_test.php new file mode 100644 index 0000000000000..11784c4dc04bf --- /dev/null +++ b/grade/tests/output/penalty_indicator_test.php @@ -0,0 +1,90 @@ +. + +namespace core_grades\output; + +use advanced_testcase; + +/** + * Test class for penalty_indicator + * + * @package core_grades + * @copyright 2024 Catalyst IT Australia Pty Ltd + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +final class penalty_indicator_test extends advanced_testcase { + /** + * Data provider for test_export_for_template + * @return array + */ + public static function export_for_template_provider(): array { + return [ + // Default icon, with max grade. + [ + 'html' => << + + + + 90.00 / 100.00 + +EOD, + 'icon' => [], + 'penalty' => 10, + 'finalgrade' => 90, + 'maxgrade' => 100, + ], + // Custom icon, without max grade. + [ + 'html' => << + + + + 90.00 + +EOD, + 'icon' => ['name' => 'i/flagged', 'component' => 'core'], + 'penalty' => 10, + 'finalgrade' => 90, + 'maxgrade' => null, + ], + ]; + } + + /** + * Test penalty_indicator + * + * @dataProvider export_for_template_provider + * + * @covers \core_grades\output\penalty_indicator + * + * @param string $expectedhtml The expected html + * @param array $icon icon to display before the penalty + * @param float $penalty The penalty + * @param float $finalgrade The final grade + * @param float|null $maxgrade The max grade + */ + public function test_export_for_template(string $expectedhtml, array $icon, float $penalty, + float $finalgrade, ?float $maxgrade): void { + global $PAGE; + $indicator = new \core_grades\output\penalty_indicator(2, $penalty, $finalgrade, $maxgrade, $icon); + $renderer = $PAGE->get_renderer('core_grades'); + $html = $renderer->render_penalty_indicator($indicator); + + $this->assertEquals($expectedhtml, $html); + } +} diff --git a/lang/en/grades.php b/lang/en/grades.php index ac1620e57c379..669b874bf385b 100644 --- a/lang/en/grades.php +++ b/lang/en/grades.php @@ -334,6 +334,7 @@ $string['gradepass'] = 'Grade to pass'; $string['gradepass_help'] = 'This setting determines the minimum grade required to pass. The value is used in activity and course completion, and in the gradebook, where pass grades are highlighted in green and fail grades in red.'; $string['gradepassgreaterthangrade'] = 'The grade to pass can not be greater than the maximum possible grade {$a}'; +$string['gradepenalty_indicator_info'] = 'Late penalty applied -{$a} marks'; $string['gradepointdefault'] = 'Grade point default'; $string['gradepointdefault_help'] = 'This setting determines the default value for the grade point value available in a grade item.'; $string['gradepointdefault_validateerror'] = 'This setting must be an integer between 1 and the grade point maximum.';