Merge branch 'MDL-77029-master' of https://github.com/ilyatregubov/moodle

This commit is contained in:
Andrew Nicols 2023-03-28 12:37:01 +08:00
commit ad15209e1f
11 changed files with 268 additions and 50 deletions

View File

@ -2215,7 +2215,7 @@ class grade_structure {
*/
public function get_locking_link(array $element, object $gpr, array $langstrings): ?string {
if (has_capability('moodle/grade:manage', $this->context)) {
if (has_capability('moodle/grade:manage', $this->context) && isset($element['object'])) {
$title = '';
$url = new moodle_url('/grade/edit/tree/action.php',
['id' => $this->courseid, 'sesskey' => sesskey(), 'eid' => $element['eid']]);
@ -2311,7 +2311,7 @@ class grade_structure {
public function get_edit_calculation_link(array $element, object $gpr,
string $editcalculationstrings): ?string {
if (has_capability('moodle/grade:manage', $this->context)) {
if (has_capability('moodle/grade:manage', $this->context) && isset($element['object'])) {
$object = $element['object'];
$isscale = $object->gradetype == GRADE_TYPE_SCALE;
$isvalue = $object->gradetype == GRADE_TYPE_VALUE;
@ -2345,6 +2345,24 @@ class grade_structure {
return html_writer::link($urlnew, $title,
['class' => 'dropdown-item', 'aria-label' => $title, 'aria-current' => $active, 'role' => 'menuitem']);
}
/**
* Returns link to sort grade item column
*
* @param moodle_url $sortlink A base link for sorting
* @param object $gpr A grade_plugin_return object
* @param string $title Language string
* @param string $direction Direction od sorting
* @return string
*/
public function get_sorting_link(moodle_url $sortlink, object $gpr, string $title, string $direction = 'asc'): string {
$sortlink->param('sort', $direction);
$gpr->add_url_params($sortlink);
return html_writer::link($sortlink, $title,
['class' => 'dropdown-item', 'aria-label' => $title, 'role' => 'menuitem']);
}
}
/**

View File

@ -6,6 +6,6 @@ define("gradereport_grader/stickycolspan",["exports"],(function(_exports){Object
* @copyright 2022 Bas Brands <bas@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
const SELECTORS_GRADEPARENT=".gradeparent",SELECTORS_STUDENTHEADER="#studentheader",SELECTORS_TABLEHEADER="th.header",SELECTORS_BEHAT="body.behat-site";_exports.init=()=>{if(document.querySelector(SELECTORS_BEHAT))return;const grader=document.querySelector(SELECTORS_GRADEPARENT),studentHeader=grader.querySelector(SELECTORS_STUDENTHEADER),leftOffset=getComputedStyle(studentHeader).getPropertyValue("left"),rightOffset=getComputedStyle(studentHeader).getPropertyValue("right"),tableHeaders=grader.querySelectorAll(SELECTORS_TABLEHEADER);for(let i=0;i<tableHeaders.length;i++)if(tableHeaders[i].colSpan>1){const addOffset=tableHeaders[i].offsetWidth-studentHeader.offsetWidth;window.right_to_left()?tableHeaders[i].style.right="calc("+rightOffset+" - "+addOffset+"px )":tableHeaders[i].style.left="calc("+leftOffset+" - "+addOffset+"px )"}else tableHeaders[i].style.zIndex=tableHeaders.length-i}}));
const SELECTORS_GRADEPARENT=".gradeparent",SELECTORS_STUDENTHEADER="#studentheader",SELECTORS_TABLEHEADER="th.header",SELECTORS_BEHAT="body.behat-site",SELECTORS_TABLEHEADING="tr.heading";_exports.init=()=>{if(document.querySelector(SELECTORS_BEHAT))return;const grader=document.querySelector(SELECTORS_GRADEPARENT),studentHeader=grader.querySelector(SELECTORS_STUDENTHEADER),leftOffset=getComputedStyle(studentHeader).getPropertyValue("left"),rightOffset=getComputedStyle(studentHeader).getPropertyValue("right"),tableHeaders=grader.querySelectorAll(SELECTORS_TABLEHEADER);let i=0;tableHeaders.forEach((tableHeader=>{if(tableHeader.colSpan>1){const addOffset=tableHeader.offsetWidth-studentHeader.offsetWidth;window.right_to_left()?tableHeader.style.right="calc("+rightOffset+" - "+addOffset+"px )":tableHeader.style.left="calc("+leftOffset+" - "+addOffset+"px )"}else tableHeader.style.zIndex=tableHeaders.length-i;i++})),grader.querySelector(SELECTORS_TABLEHEADING).style.zIndex=tableHeaders.length+1}}));
//# sourceMappingURL=stickycolspan.min.js.map

View File

@ -1 +1 @@
{"version":3,"file":"stickycolspan.min.js","sources":["../src/stickycolspan.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Javascript module for fixing the position of sticky headers with multiple colspans\n *\n * @module gradereport_grader/stickycolspan\n * @copyright 2022 Bas Brands <bas@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nconst SELECTORS = {\n GRADEPARENT: '.gradeparent',\n STUDENTHEADER: '#studentheader',\n TABLEHEADER: 'th.header',\n BEHAT: 'body.behat-site',\n AVERAGEROW: 'tr.lastrow',\n};\n\n/**\n * Initialize module\n */\nexport const init = () => {\n if (document.querySelector(SELECTORS.BEHAT)) {\n return;\n }\n const grader = document.querySelector(SELECTORS.GRADEPARENT);\n const studentHeader = grader.querySelector(SELECTORS.STUDENTHEADER);\n const leftOffset = getComputedStyle(studentHeader).getPropertyValue('left');\n const rightOffset = getComputedStyle(studentHeader).getPropertyValue('right');\n\n const tableHeaders = grader.querySelectorAll(SELECTORS.TABLEHEADER);\n\n for (let i = 0; i < tableHeaders.length; i++) {\n if (tableHeaders[i].colSpan > 1) {\n const addOffset = (tableHeaders[i].offsetWidth - studentHeader.offsetWidth);\n if (window.right_to_left()) {\n tableHeaders[i].style.right = 'calc(' + rightOffset + ' - ' + addOffset + 'px )';\n } else {\n tableHeaders[i].style.left = 'calc(' + leftOffset + ' - ' + addOffset + 'px )';\n }\n } else {\n tableHeaders[i].style.zIndex = tableHeaders.length - i;\n }\n }\n\n};\n"],"names":["SELECTORS","document","querySelector","grader","studentHeader","leftOffset","getComputedStyle","getPropertyValue","rightOffset","tableHeaders","querySelectorAll","i","length","colSpan","addOffset","offsetWidth","window","right_to_left","style","right","left","zIndex"],"mappings":";;;;;;;;MAuBMA,sBACW,eADXA,wBAEa,iBAFbA,sBAGW,YAHXA,gBAIK,gCAOS,QACZC,SAASC,cAAcF,8BAGrBG,OAASF,SAASC,cAAcF,uBAChCI,cAAgBD,OAAOD,cAAcF,yBACrCK,WAAaC,iBAAiBF,eAAeG,iBAAiB,QAC9DC,YAAcF,iBAAiBF,eAAeG,iBAAiB,SAE/DE,aAAeN,OAAOO,iBAAiBV,2BAExC,IAAIW,EAAI,EAAGA,EAAIF,aAAaG,OAAQD,OACjCF,aAAaE,GAAGE,QAAU,EAAG,OACvBC,UAAaL,aAAaE,GAAGI,YAAcX,cAAcW,YAC3DC,OAAOC,gBACPR,aAAaE,GAAGO,MAAMC,MAAQ,QAAUX,YAAc,MAAQM,UAAY,OAE1EL,aAAaE,GAAGO,MAAME,KAAO,QAAUf,WAAa,MAAQS,UAAY,YAG5EL,aAAaE,GAAGO,MAAMG,OAASZ,aAAaG,OAASD"}
{"version":3,"file":"stickycolspan.min.js","sources":["../src/stickycolspan.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Javascript module for fixing the position of sticky headers with multiple colspans\n *\n * @module gradereport_grader/stickycolspan\n * @copyright 2022 Bas Brands <bas@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nconst SELECTORS = {\n GRADEPARENT: '.gradeparent',\n STUDENTHEADER: '#studentheader',\n TABLEHEADER: 'th.header',\n BEHAT: 'body.behat-site',\n AVERAGEROW: 'tr.lastrow',\n TABLEHEADING: 'tr.heading',\n};\n\n/**\n * Initialize module\n */\nexport const init = () => {\n if (document.querySelector(SELECTORS.BEHAT)) {\n return;\n }\n const grader = document.querySelector(SELECTORS.GRADEPARENT);\n const studentHeader = grader.querySelector(SELECTORS.STUDENTHEADER);\n const leftOffset = getComputedStyle(studentHeader).getPropertyValue('left');\n const rightOffset = getComputedStyle(studentHeader).getPropertyValue('right');\n\n const tableHeaders = grader.querySelectorAll(SELECTORS.TABLEHEADER);\n let i = 0;\n tableHeaders.forEach((tableHeader) => {\n if (tableHeader.colSpan > 1) {\n const addOffset = (tableHeader.offsetWidth - studentHeader.offsetWidth);\n if (window.right_to_left()) {\n tableHeader.style.right = 'calc(' + rightOffset + ' - ' + addOffset + 'px )';\n } else {\n tableHeader.style.left = 'calc(' + leftOffset + ' - ' + addOffset + 'px )';\n }\n } else {\n tableHeader.style.zIndex = tableHeaders.length - i;\n }\n i++;\n });\n\n let tableHeader = grader.querySelector(SELECTORS.TABLEHEADING);\n tableHeader.style.zIndex = tableHeaders.length + 1;\n\n\n};\n"],"names":["SELECTORS","document","querySelector","grader","studentHeader","leftOffset","getComputedStyle","getPropertyValue","rightOffset","tableHeaders","querySelectorAll","i","forEach","tableHeader","colSpan","addOffset","offsetWidth","window","right_to_left","style","right","left","zIndex","length"],"mappings":";;;;;;;;MAuBMA,sBACW,eADXA,wBAEa,iBAFbA,sBAGW,YAHXA,gBAIK,kBAJLA,uBAMY,2BAME,QACZC,SAASC,cAAcF,8BAGrBG,OAASF,SAASC,cAAcF,uBAChCI,cAAgBD,OAAOD,cAAcF,yBACrCK,WAAaC,iBAAiBF,eAAeG,iBAAiB,QAC9DC,YAAcF,iBAAiBF,eAAeG,iBAAiB,SAE/DE,aAAeN,OAAOO,iBAAiBV,2BACzCW,EAAI,EACRF,aAAaG,SAASC,iBACdA,YAAYC,QAAU,EAAG,OACnBC,UAAaF,YAAYG,YAAcZ,cAAcY,YACvDC,OAAOC,gBACPL,YAAYM,MAAMC,MAAQ,QAAUZ,YAAc,MAAQO,UAAY,OAEtEF,YAAYM,MAAME,KAAO,QAAUhB,WAAa,MAAQU,UAAY,YAGxEF,YAAYM,MAAMG,OAASb,aAAac,OAASZ,EAErDA,OAGcR,OAAOD,cAAcF,wBAC3BmB,MAAMG,OAASb,aAAac,OAAS"}

View File

@ -27,6 +27,7 @@ const SELECTORS = {
TABLEHEADER: 'th.header',
BEHAT: 'body.behat-site',
AVERAGEROW: 'tr.lastrow',
TABLEHEADING: 'tr.heading',
};
/**
@ -42,18 +43,23 @@ export const init = () => {
const rightOffset = getComputedStyle(studentHeader).getPropertyValue('right');
const tableHeaders = grader.querySelectorAll(SELECTORS.TABLEHEADER);
for (let i = 0; i < tableHeaders.length; i++) {
if (tableHeaders[i].colSpan > 1) {
const addOffset = (tableHeaders[i].offsetWidth - studentHeader.offsetWidth);
let i = 0;
tableHeaders.forEach((tableHeader) => {
if (tableHeader.colSpan > 1) {
const addOffset = (tableHeader.offsetWidth - studentHeader.offsetWidth);
if (window.right_to_left()) {
tableHeaders[i].style.right = 'calc(' + rightOffset + ' - ' + addOffset + 'px )';
tableHeader.style.right = 'calc(' + rightOffset + ' - ' + addOffset + 'px )';
} else {
tableHeaders[i].style.left = 'calc(' + leftOffset + ' - ' + addOffset + 'px )';
tableHeader.style.left = 'calc(' + leftOffset + ' - ' + addOffset + 'px )';
}
} else {
tableHeaders[i].style.zIndex = tableHeaders.length - i;
tableHeader.style.zIndex = tableHeaders.length - i;
}
}
i++;
});
let tableHeader = grader.querySelector(SELECTORS.TABLEHEADING);
tableHeader.style.zIndex = tableHeaders.length + 1;
};

View File

@ -33,6 +33,7 @@ $page = optional_param('page', 0, PARAM_INT); // active page
$edit = optional_param('edit', -1, PARAM_BOOL); // sticky editting mode
$sortitemid = optional_param('sortitemid', 0, PARAM_ALPHANUMEXT);
$sort = optional_param('sort', '', PARAM_TEXT);
$action = optional_param('action', 0, PARAM_ALPHAEXT);
$move = optional_param('move', 0, PARAM_INT);
$type = optional_param('type', 0, PARAM_ALPHA);
@ -120,7 +121,10 @@ grade_regrade_final_grades_if_required($course);
//Initialise the grader report object that produces the table
//the class grade_report_grader_ajax was removed as part of MDL-21562
$report = new grade_report_grader($courseid, $gpr, $context, $page, $sortitemid);
if ($sort) {
$sort = strtoupper($sort);
}
$report = new grade_report_grader($courseid, $gpr, $context, $page, $sortitemid, $sort);
$numusers = $report->get_numusers(true, true);
$actionbar = new \gradereport_grader\output\action_bar($context, $report, $numusers);

View File

@ -121,8 +121,9 @@ class grade_report_grader extends grade_report {
* @param string $context
* @param int $page The current page being viewed (when report is paged)
* @param int $sortitemid The id of the grade_item by which to sort the table
* @param string $sort Sorting direction
*/
public function __construct($courseid, $gpr, $context, $page=null, $sortitemid=null) {
public function __construct($courseid, $gpr, $context, $page=null, $sortitemid=null, string $sort = '') {
global $CFG;
parent::__construct($courseid, $gpr, $context, $page);
@ -161,7 +162,7 @@ class grade_report_grader extends grade_report {
$this->setup_groups();
$this->setup_users();
$this->setup_sortitemid();
$this->setup_sortitemid($sort);
$this->overridecat = (bool)get_config('moodle', 'grade_overridecat');
}
@ -330,8 +331,10 @@ class grade_report_grader extends grade_report {
* Setting the sort order, this depends on last state
* all this should be in the new table class that we might need to use
* for displaying grades.
* @param string $sort sorting direction
*/
private function setup_sortitemid() {
private function setup_sortitemid(string $sort = '') {
global $SESSION;
@ -342,7 +345,7 @@ class grade_report_grader extends grade_report {
if ($this->sortitemid) {
if (!isset($SESSION->gradeuserreport->sort)) {
$this->sortorder = $SESSION->gradeuserreport->sort = 'ASC';
} else {
} else if (!$sort) {
// this is the first sort, i.e. by last name
if (!isset($SESSION->gradeuserreport->sortitemid)) {
$this->sortorder = $SESSION->gradeuserreport->sort = 'ASC';
@ -373,6 +376,12 @@ class grade_report_grader extends grade_report {
$this->sortorder = 'ASC';
}
}
// If explicit sorting direction exists.
if ($sort) {
$this->sortorder = $sort;
$SESSION->gradeuserreport->sort = $sort;
}
}
/**
@ -411,7 +420,13 @@ class grade_report_grader extends grade_report {
$this->groupwheresql_params, $enrolledparams, $relatedctxparams);
$sortjoin = "LEFT JOIN {grade_grades} g ON g.userid = u.id AND g.itemid = $this->sortitemid";
$sort = "g.finalgrade $this->sortorder, u.idnumber, u.lastname, u.firstname, u.email";
if ($this->sortorder == 'ASC') {
$sort = $DB->sql_order_by_null('g.finalgrade');
} else {
$sort = $DB->sql_order_by_null('g.finalgrade', SORT_DESC);
}
$sort .= ", u.idnumber, u.lastname, u.firstname, u.email";
} else {
$sortjoin = '';
@ -639,7 +654,9 @@ class grade_report_grader extends grade_report {
$studentheader->scope = 'col';
$studentheader->header = true;
$studentheader->id = 'studentheader';
$studentheader->text = $arrows['studentname'];
$element = ['type' => 'userfield', 'name' => 'fullname'];
$studentheader->text = $arrows['studentname'] . $this->get_cell_action_menu($element, 'gradeitem');
$headerrow->cells[] = $studentheader;
foreach ($extrafields as $field) {
@ -647,7 +664,8 @@ class grade_report_grader extends grade_report {
$fieldheader->attributes['class'] = 'userfield user' . $field;
$fieldheader->scope = 'col';
$fieldheader->header = true;
$fieldheader->text = $arrows[$field];
$element = ['type' => 'userfield', 'name' => $field];
$fieldheader->text = $arrows[$field] . $this->get_cell_action_menu($element, 'gradeitem');
$headerrow->cells[] = $fieldheader;
}
@ -731,7 +749,6 @@ class grade_report_grader extends grade_report {
$numusers = count($this->users);
$gradetabindex = 1;
$strgrade = $this->get_lang_string('gradenoun');
$this->get_sort_arrows();
// Get preferences once.
$quickgrading = $this->get_pref('quickgrading');
@ -803,9 +820,9 @@ class grade_report_grader extends grade_report {
$arrow = '';
if ($element['object']->id == $this->sortitemid) {
if ($this->sortorder == 'ASC') {
$arrow = $this->get_sort_arrow('up', $sortlink);
} else {
$arrow = $this->get_sort_arrow('down', $sortlink);
} else {
$arrow = $this->get_sort_arrow('up', $sortlink);
}
}
@ -1639,6 +1656,9 @@ class grade_report_grader extends grade_report {
$gradeanalysisstring = $this->get_lang_string('gradeanalysis', 'grades');
$titleasc = $this->get_lang_string('asc');
$titledesc = $this->get_lang_string('desc');
if ($element['type'] == 'grade') {
$item = $element['object']->grade_item;
if ($item->is_course_item() || $item->is_category_item()) {
@ -1656,7 +1676,8 @@ class grade_report_grader extends grade_report {
$context->gradeanalysisurl = $this->gtree->get_grade_analysis_link($element['object'], $gradeanalysisstring);
} else if (($element['type'] == 'item') ||
($element['type'] == 'categoryitem') ||
($element['type'] == 'courseitem')) {
($element['type'] == 'courseitem') ||
($element['type'] == 'userfield')) {
if ($element['type'] == 'item') {
foreach ($this->get_report_links($this->context, $this->courseid, $element, $this->gpr, $mode)
@ -1667,9 +1688,14 @@ class grade_report_grader extends grade_report {
$context->advancedgradingurl = $this->gtree->get_advanced_grading_link($element, $this->gpr);
}
if ($element['type'] == 'item') {
$context->divider1 = true;
}
if (!empty($USER->editing)) {
$context->divider = true;
if ($element['type'] !== 'userfield') {
$context->divider1 = true;
$context->divider2 = true;
}
if ($element['type'] == 'item') {
$context->editurl = $this->gtree->get_edit_link($element, $this->gpr, $editstrings);
}
@ -1677,12 +1703,36 @@ class grade_report_grader extends grade_report {
$context->editcalculationurl =
$this->gtree->get_edit_calculation_link($element, $this->gpr, $editcalculationstrings);
$object = $element['object'];
if ($object->itemmodule !== 'quiz') {
$context->hideurl = $this->gtree->get_hiding_link($element, $this->gpr, $hidestrings);
if (isset($element['object'])) {
$object = $element['object'];
if ($object->itemmodule !== 'quiz') {
$context->hideurl = $this->gtree->get_hiding_link($element, $this->gpr, $hidestrings);
}
}
$context->lockurl = $this->gtree->get_locking_link($element, $this->gpr, $lockstrings);
}
// Sorting item.
$sortlink = clone($this->baseurl);
if (isset($element['object']->id)) {
$sortlink->param('sortitemid', $element['object']->id);
} else if ($element['type'] == 'userfield') {
$sortlink->param('sortitemid', $element['name']);
}
if (($element['type'] == 'userfield') && ($element['name'] == 'fullname')) {
$sortlink->param('sortitemid', 'firstname');
$context->ascendingfirstnameurl = $this->gtree->get_sorting_link($sortlink, $this->gpr, $titleasc);
$context->descendingfirstnameurl = $this->gtree->get_sorting_link($sortlink, $this->gpr, $titledesc, 'desc');
$sortlink->param('sortitemid', 'lastname');
$context->ascendinglastnameurl = $this->gtree->get_sorting_link($sortlink, $this->gpr, $titleasc);
$context->descendinglastnameurl = $this->gtree->get_sorting_link($sortlink, $this->gpr, $titledesc, 'desc');
} else {
$context->ascendingurl = $this->gtree->get_sorting_link($sortlink, $this->gpr, $titleasc);
$context->descendingurl = $this->gtree->get_sorting_link($sortlink, $this->gpr, $titledesc, 'desc');
}
} else if ($element['type'] == 'category') {
$categoryid = $element['object']->id;
@ -1712,7 +1762,7 @@ class grade_report_grader extends grade_report {
$this->gtree->get_category_view_mode_link($url, $strswitchwhole, 'switch_whole', $fullmode);
if (!empty($USER->editing)) {
$context->divider = true;
$context->divider1 = true;
$context->editurl = $this->gtree->get_edit_link($element, $this->gpr, $editstrings);
$context->hideurl = $this->gtree->get_hiding_link($element, $this->gpr, $hidestrings);
$context->lockurl = $this->gtree->get_locking_link($element, $this->gpr, $lockstrings);
@ -1720,7 +1770,11 @@ class grade_report_grader extends grade_report {
}
$context->dataid = $element['object']->id;
if (isset($element['object'])) {
$context->dataid = $element['object']->id;
} else if ($element['type'] == 'userfield') {
$context->dataid = $element['name'];
}
} else if ($mode == 'user') {
foreach ($this->get_report_links($this->context, $this->courseid, $element, $this->gpr, $mode)
as $count => $reportlink) {
@ -1731,7 +1785,8 @@ class grade_report_grader extends grade_report {
}
if (!empty($USER->editing) || isset($context->gradeanalysisurl) || isset($context->gradesonlyurl)
|| isset($context->aggregatesonlyurl) || isset($context->fullmodeurl) || isset($context->reporturl0)) {
|| isset($context->aggregatesonlyurl) || isset($context->fullmodeurl) || isset($context->reporturl0)
|| isset($context->ascendingurl) || isset($context->ascendingfirstnameurl)) {
return $OUTPUT->render_from_template('gradereport_grader/cellmenu', $context);
}
return '';
@ -1949,13 +2004,9 @@ class grade_report_grader extends grade_report {
* @return array An associative array of HTML sorting links+arrows
*/
public function get_sort_arrows(array $extrafields = array()) {
global $OUTPUT, $CFG;
global $CFG;
$arrows = array();
$strsortasc = $this->get_lang_string('sortasc', 'grades');
$strsortdesc = $this->get_lang_string('sortdesc', 'grades');
$iconasc = $OUTPUT->pix_icon('t/sort_asc', $strsortasc, '', array('class' => 'iconsmall sorticon'));
$icondesc = $OUTPUT->pix_icon('t/sort_desc', $strsortdesc, '', array('class' => 'iconsmall sorticon'));
$sortlink = clone($this->baseurl);
// Sourced from tablelib.php
// Check the full name display for sortable fields.
@ -1977,7 +2028,13 @@ class grade_report_grader extends grade_report {
new moodle_url($this->baseurl, array('sortitemid' => $name)), $this->get_lang_string($name)
);
if ($this->sortitemid == $name) {
$arrows['studentname'] .= $this->sortorder == 'ASC' ? $iconasc : $icondesc;
$sortlink->param('sortitemid', $name);
if ($this->sortorder == 'ASC') {
$sorticon = $this->get_sort_arrow('down', $sortlink);
} else {
$sorticon = $this->get_sort_arrow('up', $sortlink);
}
$arrows['studentname'] .= $sorticon;
}
$arrows['studentname'] .= ' / ';
}
@ -1991,11 +2048,14 @@ class grade_report_grader extends grade_report {
$arrows[$field] = $fieldlink;
if ($field == $this->sortitemid) {
$sortlink->param('sortitemid', $field);
if ($this->sortorder == 'ASC') {
$arrows[$field] .= $iconasc;
$sorticon = $this->get_sort_arrow('down', $sortlink);
} else {
$arrows[$field] .= $icondesc;
$sorticon = $this->get_sort_arrow('up', $sortlink);
}
$arrows[$field] .= $sorticon;
}
}

View File

@ -174,7 +174,9 @@
}
.path-grade-report-grader .gradeparent .sorticon {
margin-left: 3px;
margin-left: 5px;
vertical-align: middle;
margin-right: 1px;
}
.path-grade-report-grader .gradeparent .gradevalue {
@ -214,10 +216,6 @@
text-align: center;
}
.path-grade-report-grader .action-menu {
padding-left: 10px;
}
.path-grade-report-grader .dropdown-menu {
width: max-content;
}

View File

@ -23,7 +23,15 @@
"editurl": "<a class='dropdown-item' aria-label='Edit grade' role='menuitem' href='grade/edit/tree/grade.php?courseid=13&itemid=608&userid=85&gpr_type=report&gpr_plugin=grader&gpr_courseid=13'>Edit grade</a>",
"hideurl": "<a class='dropdown-item' aria-label='Hide' role='menuitem' href='grade/edit/tree/action.php?id=13&sesskey=sMAOMLAAN5&eid=n608u85&gpr_type=report&gpr_plugin=grader&gpr_courseid=13&action=hide'>Hide</a>",
"reporturl0": "<a class='dropdown-item' aria-label='Single view for this user' role='menuitem' href='grade/report/singleview/index.php?id=13&amp;itemid=39&amp;item=user&amp;gpr_type=report&amp;gpr_plugin=grader&amp;gpr_courseid=13'>Single view for this user</a>",
"reporturl1": "<a class='dropdown-item' aria-label='User report' role='menuitem' href='grade/report/user/index.php?userid=39&amp;id=13&amp;gpr_type=report&amp;gpr_plugin=grader&amp;gpr_courseid=13'>User report</a>"
"reporturl1": "<a class='dropdown-item' aria-label='User report' role='menuitem' href='grade/report/user/index.php?userid=39&amp;id=13&amp;gpr_type=report&amp;gpr_plugin=grader&amp;gpr_courseid=13'>User report</a>",
"ascendingurl": "<a class='dropdown-item' aria-label='Ascending' role='menuitem' href='index.php?id=13&amp;sortitemid=email&amp;sort=asc&amp;gpr_type=report&amp;gpr_plugin=grader&amp;gpr_courseid=13'>Ascending</a>",
"descendingurl": "<a class='dropdown-item' aria-label='Descending' role='menuitem' href='index.php?id=13&amp;sortitemid=email&amp;sort=desc&amp;gpr_type=report&amp;gpr_plugin=grader&amp;gpr_courseid=13'>Descending</a>",
"ascendingfirstnameurl": "<a class='dropdown-item' aria-label='Ascending' role='menuitem' href='index.php?id=13&amp;sortitemid=firstname&amp;sort=asc&amp;gpr_type=report&amp;gpr_plugin=grader&amp;gpr_courseid=13'>Ascending</a>",
"descendingfirstnameurl": "<a class='dropdown-item' aria-label='Descending' role='menuitem' href='index.php?id=13&amp;sortitemid=firstname&amp;sort=desc&amp;gpr_type=report&amp;gpr_plugin=grader&amp;gpr_courseid=13'>Descending</a>",
"ascendinglastnameurl": "<a class='dropdown-item' aria-label='Ascending' role='menuitem' href='index.php?id=13&amp;sortitemid=lastname&amp;sort=asc&amp;gpr_type=report&amp;gpr_plugin=grader&amp;gpr_courseid=13'>Ascending</a>",
"descendinglastnameurl": "<a class='dropdown-item' aria-label='Descending' role='menuitem' href='index.php?id=13&amp;sortitemid=lastname&amp;sort=desc&amp;gpr_type=report&amp;gpr_plugin=grader&amp;gpr_courseid=13'>Descending</a>",
"divider1": "true",
"divider2": "true"
}
}}
<div class="action-menu mb-1 moodle-actionmenu grader">
@ -43,9 +51,25 @@
{{#gradesonlyurl}}{{{gradesonlyurl}}}{{/gradesonlyurl}}
{{#aggregatesonlyurl}}{{{aggregatesonlyurl}}}{{/aggregatesonlyurl}}
{{#fullmodeurl}}{{{fullmodeurl}}}{{/fullmodeurl}}
{{#divider}}
{{#advancedgradingurl}}{{{advancedgradingurl}}}{{/advancedgradingurl}}
{{#divider1}}
<div class="dropdown-divider" role="separator"></div>
{{/divider}}
{{/divider1}}
{{#ascendingfirstnameurl}}
<h6 class="dropdown-header">{{#str}} firstname, moodle {{/str}}</h6>
{{{ascendingfirstnameurl}}}
{{{descendingfirstnameurl}}}
<h6 class="dropdown-header">{{#str}} lastname, moodle {{/str}}</h6>
{{{ascendinglastnameurl}}}
{{{descendinglastnameurl}}}
{{/ascendingfirstnameurl}}
{{#ascendingurl}}
{{{ascendingurl}}}
{{{descendingurl}}}
{{/ascendingurl}}
{{#divider2}}
<div class="dropdown-divider" role="separator"></div>
{{/divider2}}
{{#hideurl}}{{{hideurl}}}{{/hideurl}}
{{#lockurl}}{{{lockurl}}}{{/lockurl}}
</div>

View File

@ -242,4 +242,16 @@ class behat_gradereport_grader extends behat_base {
return "//table[@id='user-grades']//*[@data-id='" . $userid . "']";
}
/**
* Clicks on given user profile field menu.
*
* @Given /^I click on user profile field menu "([^"]*)"$/
* @param string $field
*/
public function i_click_on_user_profile_field_menu(string $field) {
$xpath = "//table[@id='user-grades']//*[@data-id='" . $field . "']";
$this->execute("behat_general::i_click_on", array($this->escape($xpath), "xpath_element"));
}
}

View File

@ -0,0 +1,97 @@
@gradereport @gradereport_grader
Feature: We can sort grades/user fields on the grader report
In order to manage grades on grader report
As a teacher
I need to be able to sort grades or user fields.
Background:
Given the following "courses" exist:
| fullname | shortname | format |
| Course 1 | C1 | topics |
And the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
| student1 | StudentA | 2 | d@example.com |
| student2 | StudentB | 4 | a@example.com |
| student3 | StudentC | 3 | c@example.com |
| student4 | StudentD | 1 | b@example.com |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
| student2 | C1 | student |
| student3 | C1 | student |
| student4 | C1 | student |
And the following "activities" exist:
| activity | course | section | name | intro | assignsubmission_onlinetext_enabled | submissiondrafts |
| assign | C1 | 1 | Test assignment name 1 | Submit your online text | 1 | 0 |
And the following "mod_assign > submissions" exist:
| assign | user | onlinetext |
| Test assignment name 1 | student1 | This is a submission for assignment 1 |
| Test assignment name 1 | student2 | This is a submission for assignment 1 |
| Test assignment name 1 | student3 | This is a submission for assignment 1 |
| Test assignment name 1 | student4 | This is a submission for assignment 1 |
And the following "grade items" exist:
| itemname | grademin | grademax | course |
| Manual grade | 20 | 40 | C1 |
And the following "grade grades" exist:
| gradeitem | user | grade |
| Test assignment name 1 | student1 | 80 |
| Test assignment name 1 | student2 | 40 |
| Test assignment name 1 | student3 | 60 |
And I log in as "teacher1"
@javascript
Scenario: Sort grades or user fields on grader report
When I am on "Course 1" course homepage with editing mode on
And I navigate to "View > Grader report" in the course gradebook
# Default sorting is lastname ascending.
And "StudentD 1" "table_row" should appear before "StudentA 2" "table_row"
And "StudentA 2" "table_row" should appear before "StudentC 3" "table_row"
And "StudentC 3" "table_row" should appear before "StudentB 4" "table_row"
# Sort by grades in descending order.
And I click on grade item menu "Test assignment name 1"
And I choose "Descending" in the open action menu
And I wait until the page is ready
Then "StudentA 2" "table_row" should appear before "StudentC 3" "table_row"
And "StudentC 3" "table_row" should appear before "StudentB 4" "table_row"
And "StudentB 4" "table_row" should appear before "StudentD 1" "table_row"
# Sort by grades in ascending order.
And I click on grade item menu "Test assignment name 1"
And I choose "Ascending" in the open action menu
And I wait until the page is ready
Then "StudentD 1" "table_row" should appear before "StudentB 4" "table_row"
And "StudentB 4" "table_row" should appear before "StudentC 3" "table_row"
And "StudentC 3" "table_row" should appear before "StudentA 2" "table_row"
# Sort by email in ascending order.
And I click on user profile field menu "email"
And I choose "Ascending" in the open action menu
And I wait until the page is ready
Then "StudentB 4" "table_row" should appear before "StudentD 1" "table_row"
And "StudentD 1" "table_row" should appear before "StudentC 3" "table_row"
And "StudentC 3" "table_row" should appear before "StudentA 2" "table_row"
And I click on user profile field menu "email"
# Sort by email in descending order.
And I choose "Descending" in the open action menu
And I wait until the page is ready
Then "StudentA 2" "table_row" should appear before "StudentC 3" "table_row"
And "StudentC 3" "table_row" should appear before "StudentD 1" "table_row"
And "StudentD 1" "table_row" should appear before "StudentB 4" "table_row"
# Sort by firstname in ascending order.
And I click on "First name" "link"
And I wait until the page is ready
Then "StudentA 2" "table_row" should appear before "StudentB 4" "table_row"
And "StudentB 4" "table_row" should appear before "StudentC 3" "table_row"
And "StudentC 3" "table_row" should appear before "StudentD 1" "table_row"
# Sort by firstname in descending order.
And I click on "First name" "link"
And I wait until the page is ready
Then "StudentD 1" "table_row" should appear before "StudentC 3" "table_row"
And "StudentC 3" "table_row" should appear before "StudentB 4" "table_row"
And "StudentB 4" "table_row" should appear before "StudentA 2" "table_row"
# Sort by lastname in ascending order.
And I click on "Last name" "link"
And I wait until the page is ready
Then "StudentD 1" "table_row" should appear before "StudentA 2" "table_row"
And "StudentA 2" "table_row" should appear before "StudentC 3" "table_row"
And "StudentC 3" "table_row" should appear before "StudentB 4" "table_row"

View File

@ -443,7 +443,6 @@ abstract class grade_report {
$pix = ['up' => 't/sort_desc', 'down' => 't/sort_asc'];
$matrix = ['up' => 'desc', 'down' => 'asc'];
$strsort = $this->get_lang_string($matrix[$direction], 'moodle');
$arrow = $OUTPUT->pix_icon($pix[$direction], '', '', ['class' => 'sorticon']);
return html_writer::link($sortlink, $arrow, ['title' => $strsort, 'aria-label' => $strsort]);
}