From 7656f5b6b0e21b747ac358dcc7cd0df2ffcd0146 Mon Sep 17 00:00:00 2001 From: Ilya Tregubov Date: Fri, 16 Dec 2022 16:14:34 +0700 Subject: [PATCH] MDL-76147 gradereport_grader: Move grade items and categories icons to action menu. --- grade/lib.php | 240 ++++++++++--- .../grader/lang/en/gradereport_grader.php | 1 + grade/report/grader/lib.php | 314 +++++++++--------- grade/report/grader/styles.css | 20 +- .../{grademenu.mustache => cellmenu.mustache} | 25 +- grade/report/lib.php | 34 +- .../singleview/classes/report/singleview.php | 3 +- .../lang/en/gradereport_singleview.php | 2 + grade/report/singleview/lib.php | 74 +++++ grade/report/upgrade.txt | 5 + grade/report/user/classes/report/user.php | 3 + .../report/user/lang/en/gradereport_user.php | 1 + grade/report/user/lib.php | 34 ++ lang/en/grades.php | 13 +- theme/boost/scss/moodle/grade.scss | 2 +- theme/boost/style/moodle.css | 2 +- theme/classic/style/moodle.css | 2 +- 17 files changed, 554 insertions(+), 221 deletions(-) rename grade/report/grader/templates/{grademenu.mustache => cellmenu.mustache} (50%) create mode 100644 grade/report/singleview/lib.php diff --git a/grade/lib.php b/grade/lib.php index d4828b26cc8..c6692160e6b 100644 --- a/grade/lib.php +++ b/grade/lib.php @@ -1539,11 +1539,13 @@ class grade_structure { * @param bool $withdescription Show description if defined by this item. * @param bool $fulltotal If the item is a category total, returns $categoryname."total" * instead of "Category total" or "Course total" + * @param moodle_url|null $sortlink Link to sort column. * * @return string header */ - public function get_element_header(&$element, $withlink = false, $icon = true, $spacerifnone = false, - $withdescription = false, $fulltotal = false) { + public function get_element_header(array &$element, bool $withlink = false, bool $icon = true, + bool $spacerifnone = false, bool $withdescription = false, bool $fulltotal = false, + ?moodle_url $sortlink = null) { $header = ''; if ($icon) { @@ -1559,15 +1561,22 @@ class grade_structure { return $header; } - if ($withlink && $url = $this->get_activity_link($element)) { - $a = new stdClass(); - $a->name = get_string('modulename', $element['object']->itemmodule); - $a->title = $titleunescaped; - $title = get_string('linktoactivity', 'grades', $a); + if ($sortlink) { + $url = $sortlink; + $header = html_writer::link($url, $header, + ['title' => $titleunescaped, 'class' => 'gradeitemheader']); + } - $header = html_writer::link($url, $header, array('title' => $title, 'class' => 'gradeitemheader')); - } else { - $header = html_writer::span($header, 'gradeitemheader', array('title' => $titleunescaped, 'tabindex' => '0')); + if (!$sortlink) { + if ($withlink && $url = $this->get_activity_link($element)) { + $a = new stdClass(); + $a->name = get_string('modulename', $element['object']->itemmodule); + $a->title = $titleunescaped; + $title = get_string('linktoactivity', 'grades', $a); + $header = html_writer::link($url, $header, ['title' => $title, 'class' => 'gradeitemheader']); + } else { + $header = html_writer::span($header, 'gradeitemheader', ['title' => $titleunescaped, 'tabindex' => '0']); + } } if ($withdescription) { @@ -1942,10 +1951,9 @@ class grade_structure { public function get_edit_link(array $element, object $gpr, array $langstrings): ?string { $url = null; $title = ''; - if (!has_capability('moodle/grade:manage', $this->context)) { - if (!($element['type'] == 'grade') || !has_capability('moodle/grade:edit', $this->context)) { + if ((!has_capability('moodle/grade:manage', $this->context) && + (!($element['type'] == 'grade') || !has_capability('moodle/grade:edit', $this->context)))) { return null; - } } $object = $element['object']; @@ -1960,11 +1968,84 @@ class grade_structure { } $url = $gpr->add_url_params($url); $title = $langstrings[0]; + } else if (($element['type'] == 'item') || ($element['type'] == 'categoryitem') || + ($element['type'] == 'courseitem')) { + if (empty($object->outcomeid) || empty($CFG->enableoutcomes)) { + $url = new moodle_url('/grade/edit/tree/item.php', + ['courseid' => $this->courseid, 'id' => $object->id]); + } else { + $url = new moodle_url('/grade/edit/tree/outcomeitem.php', + ['courseid' => $this->courseid, 'id' => $object->id]); + } + $url = $gpr->add_url_params($url); + $title = $langstrings[1]; + } else if ($element['type'] == 'category') { + $url = new moodle_url('/grade/edit/tree/category.php', + ['courseid' => $this->courseid, 'id' => $object->id]); + $url = $gpr->add_url_params($url); + $title = $langstrings[2]; } return html_writer::link($url, $title, ['class' => 'dropdown-item', 'aria-label' => $title, 'role' => 'menuitem']); } + /** + * Returns link to the advanced grading page + * + * @param array $element An array representing an element in the grade_tree + * @param object $gpr A grade_plugin_return object + * @return string|null + */ + public function get_advanced_grading_link(array $element, object $gpr): ?string { + global $CFG; + + /** @var array static cache of the grade.php file existence flags */ + static $hasgradephp = []; + + $itemtype = $element['object']->itemtype; + $itemmodule = $element['object']->itemmodule; + $iteminstance = $element['object']->iteminstance; + $itemnumber = $element['object']->itemnumber; + + // Links only for module items that have valid instance, module and are + // called from grade_tree with valid modinfo. + if ($itemtype == 'mod' && $iteminstance && $itemmodule && $this->modinfo) { + + // Get $cm efficiently and with visibility information using modinfo. + $instances = $this->modinfo->get_instances(); + if (!empty($instances[$itemmodule][$iteminstance])) { + $cm = $instances[$itemmodule][$iteminstance]; + + // Do not add link if activity is not visible to the current user. + if ($cm->uservisible) { + if (!array_key_exists($itemmodule, $hasgradephp)) { + if (file_exists($CFG->dirroot . '/mod/' . $itemmodule . '/grade.php')) { + $hasgradephp[$itemmodule] = true; + } else { + $hasgradephp[$itemmodule] = false; + } + } + + // If module has grade.php, add link to that. + if ($hasgradephp[$itemmodule]) { + $args = array('id' => $cm->id, 'itemnumber' => $itemnumber); + if (isset($element['userid'])) { + $args['userid'] = $element['userid']; + } + + $url = new moodle_url('/mod/' . $itemmodule . '/grade.php', $args); + $title = get_string('advancedgrading', 'gradereport_grader', $itemmodule); + $gpr->add_url_params($url); + return html_writer::link($url, $title, + ['class' => 'dropdown-item', 'aria-label' => $title, 'role' => 'menuitem']); + } + } + } + } + + return null; + } + /** * Return hiding icon for give element * @@ -2032,9 +2113,8 @@ class grade_structure { * @return string|null */ public function get_hiding_link(array $element, object $gpr, array $langstrings): ?string { - if (!$element['object']->can_control_visibility() || - (!has_capability('moodle/grade:manage', $this->context) && - !has_capability('moodle/grade:hide', $this->context))) { + if (!$element['object']->can_control_visibility() || !has_capability('moodle/grade:manage', $this->context) || + !has_capability('moodle/grade:hide', $this->context)) { return null; } @@ -2135,41 +2215,41 @@ class grade_structure { */ public function get_locking_link(array $element, object $gpr, array $langstrings): ?string { - $title = ''; - $url = new moodle_url('/grade/edit/tree/action.php', - ['id' => $this->courseid, 'sesskey' => sesskey(), 'eid' => $element['eid']]); - $url = $gpr->add_url_params($url); + if (has_capability('moodle/grade:manage', $this->context)) { + $title = ''; + $url = new moodle_url('/grade/edit/tree/action.php', + ['id' => $this->courseid, 'sesskey' => sesskey(), 'eid' => $element['eid']]); + $url = $gpr->add_url_params($url); - if (($element['type'] == 'grade') && ($element['object']->grade_item->is_locked())) { - // Don't allow an unlocking action for a grade whose grade item is locked: just print a state icon. - $strparamobj = new stdClass(); - $strparamobj->itemname = $element['object']->grade_item->get_name(true, true); - $strnonunlockable = get_string('nonunlockableverbose', 'grades', $strparamobj); - $title = $langstrings[0]; - return html_writer::span($title, 'text-muted dropdown-item', ['title' => $strnonunlockable, - 'aria-label' => $title, 'role' => 'menuitem']); - } else if ($element['object']->is_locked()) { - $title = $langstrings[0]; - if (!has_capability('moodle/grade:manage', $this->context) && - !has_capability('moodle/grade:unlock', $this->context)) { - return html_writer::span($title, 'text-muted dropdown-item', - ['aria-label' => $title, 'role' => 'menuitem']); + if (($element['type'] == 'grade') && ($element['object']->grade_item->is_locked())) { + // Don't allow an unlocking action for a grade whose grade item is locked: just print a state icon. + $strparamobj = new stdClass(); + $strparamobj->itemname = $element['object']->grade_item->get_name(true, true); + $strnonunlockable = get_string('nonunlockableverbose', 'grades', $strparamobj); + $title = $langstrings[0]; + return html_writer::span($title, 'text-muted dropdown-item', ['title' => $strnonunlockable, + 'aria-label' => $title, 'role' => 'menuitem']); + } else if ($element['object']->is_locked()) { + if (has_capability('moodle/grade:unlock', $this->context)) { + $title = $langstrings[0]; + $url->param('action', 'unlock'); + } else { + return null; + } } else { - $url->param('action', 'unlock'); + if (has_capability('moodle/grade:lock', $this->context)) { + $title = $langstrings[1]; + $url->param('action', 'lock'); + } else { + return null; + } } + + return html_writer::link($url, $title, + ['class' => 'dropdown-item', 'aria-label' => $title, 'role' => 'menuitem']); } else { - $title = $langstrings[1]; - if (!has_capability('moodle/grade:manage', $this->context) && - !has_capability('moodle/grade:lock', $this->context)) { - return html_writer::span($title, 'text-muted dropdown-item', - ['aria-label' => $title, 'role' => 'menuitem']); - } else { - $url->param('action', 'lock'); - } + return null; } - - return html_writer::link($url, $title, - ['class' => 'dropdown-item', 'aria-label' => $title, 'role' => 'menuitem']); } /** @@ -2218,6 +2298,53 @@ class grade_structure { return $returnactionmenulink ? null : ''; } + + /** + * Returns link to edit calculation for a grade item. + * + * @param array $element An array representing an element in the grade_tree + * @param object $gpr A grade_plugin_return object + * @param string $editcalculationstrings Language string + * + * @return string|null + */ + public function get_edit_calculation_link(array $element, object $gpr, + string $editcalculationstrings): ?string { + + if (has_capability('moodle/grade:manage', $this->context)) { + $object = $element['object']; + $isscale = $object->gradetype == GRADE_TYPE_SCALE; + $isvalue = $object->gradetype == GRADE_TYPE_VALUE; + + // Show calculation icon only when calculation possible. + if (!$object->is_external_item() && ($isscale || $isvalue)) { + $url = new moodle_url('/grade/edit/tree/calculation.php', + ['courseid' => $this->courseid, 'id' => $object->id]); + $url = $gpr->add_url_params($url); + return html_writer::link($url, $editcalculationstrings, + ['class' => 'dropdown-item', 'aria-label' => $editcalculationstrings, 'role' => 'menuitem']); + } + } + return null; + } + + /** + * Returns link to change category view mode. + * + * @param moodle_url $url Url to grader report page + * @param string $title Menu item title + * @param string $action View mode to change to + * @param bool $active Whether link is active in dropdown + * + * @return string|null + */ + public function get_category_view_mode_link(moodle_url $url, string $title, string $action, bool $active = false): ?string { + $urlnew = $url; + $urlnew->param('action', $action); + $active = $active ? 'true' : 'false'; + return html_writer::link($urlnew, $title, + ['class' => 'dropdown-item', 'aria-label' => $title, 'aria-current' => $active, 'role' => 'menuitem']); + } } /** @@ -3051,6 +3178,27 @@ abstract class grade_helper { */ protected static $aggregationstrings = null; + /** + * Cached grade tree plugin strings + * @var array + */ + protected static $langstrings = []; + + /** + * First checks the cached language strings, then returns match if found, or uses get_string() + * to get it from the DB, caches it then returns it. + * + * @param string $strcode + * @param string|null $section Optional language section + * @return string + */ + public static function get_lang_string(string $strcode, ?string $section = null): string { + if (empty(self::$langstrings[$strcode])) { + self::$langstrings[$strcode] = get_string($strcode, $section); + } + return self::$langstrings[$strcode]; + } + /** * Gets strings commonly used by the describe plugins * diff --git a/grade/report/grader/lang/en/gradereport_grader.php b/grade/report/grader/lang/en/gradereport_grader.php index b549e0f1de0..010dfcf7ccb 100644 --- a/grade/report/grader/lang/en/gradereport_grader.php +++ b/grade/report/grader/lang/en/gradereport_grader.php @@ -48,6 +48,7 @@ $string['privacy:request:preference:grade_report_grader_collapsed_categories'] = $string['summarygrader'] = 'A table with the names of students in the first column, with assessable activities grouped by course and category across the top.'; $string['useractivitygrade'] = '{$a} grade'; $string['overriddengrade'] = 'Overridden grade'; +$string['advancedgrading'] = 'View {$a} results'; $string['cellactions'] = 'Cell actions'; // Deprecated since Moodle 4.2. diff --git a/grade/report/grader/lib.php b/grade/report/grader/lib.php index 75d2578971e..1285cf36021 100644 --- a/grade/report/grader/lib.php +++ b/grade/report/grader/lib.php @@ -596,24 +596,13 @@ class grade_report_grader extends grade_report { $rows = []; $showuserimage = $this->get_pref('showuserimage'); - // FIXME: MDL-52678 This get_capability_info is hacky and we should have an API for inserting grade row links instead. - $canseeuserreport = false; - $canseesingleview = false; - if (get_capability_info('gradereport/' . $CFG->grade_profilereport.':view')) { - $canseeuserreport = has_capability('gradereport/' . $CFG->grade_profilereport.':view', $this->context); - } - if (get_capability_info('gradereport/singleview:view')) { - $canseesingleview = has_all_capabilities(['gradereport/singleview:view', - 'moodle/grade:viewall', 'moodle/grade:edit'], $this->context); - } - $hasuserreportcell = $canseeuserreport || $canseesingleview; $viewfullnames = has_capability('moodle/site:viewfullnames', $this->context); $extrafields = \core_user\fields::get_identity_fields($this->context); $arrows = $this->get_sort_arrows($extrafields); - $colspan = 1 + $hasuserreportcell + count($extrafields); + $colspan = 1 + count($extrafields); $levels = count($this->gtree->levels) - 1; @@ -646,25 +635,17 @@ class grade_report_grader extends grade_report { $studentheader->text = $arrows['studentname']; $headerrow->cells[] = $studentheader; - if ($hasuserreportcell) { - $emptyheader = new html_table_cell(); - $headerrow->cells[] = $emptyheader; - } - foreach ($extrafields as $field) { $fieldheader = new html_table_cell(); $fieldheader->attributes['class'] = 'userfield user' . $field; $fieldheader->scope = 'col'; $fieldheader->header = true; $fieldheader->text = $arrows[$field]; - $headerrow->cells[] = $fieldheader; } $rows[] = $headerrow; - $rows = $this->get_left_icons_row($rows, $colspan); - $suspendedstring = null; $usercount = 0; @@ -705,35 +686,10 @@ class grade_report_grader extends grade_report { // when horizontally scrolling through the table contents (most noticeable when in RTL mode). // Therefore, add slight padding on the left or right when using RTL mode. $usercell->attributes['class'] .= ' pl-3'; + $usercell->text .= $this->get_cell_action_menu(['userid' => $userid], 'user'); $userrow->cells[] = $usercell; - $userreportcell = new html_table_cell(); - $userreportcell->attributes['class'] = 'userreport'; - $userreportcell->header = false; - if ($canseeuserreport) { - $a = new stdClass(); - $a->user = $fullname; - $strgradesforuser = get_string('gradesforuser', 'grades', $a); - $url = new moodle_url('/grade/report/'.$CFG->grade_profilereport.'/index.php', - ['userid' => $user->id, 'id' => $this->course->id]); - $userreportcell->text .= $OUTPUT->action_icon($url, new pix_icon('t/grades', ''), null, - ['title' => $strgradesforuser, 'aria-label' => $strgradesforuser]); - } - - if ($canseesingleview) { - $strsingleview = get_string('singleview', 'grades', $fullname); - $url = new moodle_url('/grade/report/singleview/index.php', - ['id' => $this->course->id, 'itemid' => $user->id, 'item' => 'user']); - $singleview = $OUTPUT->action_icon($url, new pix_icon('t/editstring', ''), null, - ['title' => $strsingleview, 'aria-label' => $strsingleview]); - $userreportcell->text .= $singleview; - } - - if ($userreportcell->text) { - $userrow->cells[] = $userreportcell; - } - foreach ($extrafields as $field) { $fieldcell = new html_table_cell(); $fieldcell->attributes['class'] = 'userfield user' . $field; @@ -827,62 +783,42 @@ class grade_report_grader extends grade_report { $categorycell->header = true; $categorycell->scope = 'col'; - // Print icons. - if (!empty($USER->editing)) { - $categorycell->text .= $this->get_icons($element); + $statusicons = $this->set_grade_status_icons($element); + if ($statusicons) { + $categorycell->text .= $statusicons; + $categorycell->attributes['class'] .= ' statusicons'; } $headingrow->cells[] = $categorycell; } } else { // Element is a grade_item. + + $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('move', $sortlink); } $headerlink = $this->gtree->get_element_header($element, true, - $showactivityicons, false, false, true); + true, false, false, true, $sortlink); $itemcell = new html_table_cell(); $itemcell->attributes['class'] = $type . ' ' . $catlevel . ' highlightable'. ' i'. $element['object']->id; $itemcell->attributes['data-itemid'] = $element['object']->id; - if ($element['object']->is_hidden()) { - $itemcell->attributes['class'] .= ' dimmed_text'; - } - - $singleview = ''; - - // FIXME: MDL-52678 This is extremely hacky we should have an API for inserting grade column links. - if (get_capability_info('gradereport/singleview:view')) { - if (has_all_capabilities(['gradereport/singleview:view', 'moodle/grade:viewall', - 'moodle/grade:edit'], $this->context)) { - - $strsingleview = get_string('singleview', 'grades', - $element['object']->get_name()); - $url = new moodle_url('/grade/report/singleview/index.php', [ - 'id' => $this->course->id, - 'item' => 'grade', - 'itemid' => $element['object']->id - ]); - $singleview = $OUTPUT->action_icon( - $url, - new pix_icon('t/editstring', ''), - null, - ['title' => $strsingleview, 'aria-label' => $strsingleview] - ); - } + $singleview = $this->get_cell_action_menu($element, 'gradeitem'); + $statusicons = $this->set_grade_status_icons($element); + if ($statusicons) { + $itemcell->attributes['class'] .= ' statusicons'; } $itemcell->colspan = $colspan; - $itemcell->text = $headerlink . $arrow . $singleview; + $itemcell->text = $headerlink . $arrow . $singleview . $statusicons; $itemcell->header = true; $itemcell->scope = 'col'; @@ -892,8 +828,6 @@ class grade_report_grader extends grade_report { $rows[] = $headingrow; } - $rows = $this->get_right_icons_row($rows); - // Preload scale objects for items with a scaleid and initialize tab indices. $scaleslist = []; $tabindices = []; @@ -1007,7 +941,7 @@ class grade_report_grader extends grade_report { $gradepass = ''; $context->gradepassicon = ''; } - $context->statusicons = $this->set_grade_status_icons($grade); + $context->statusicons = $this->set_grade_status_icons($element); // If in editing mode, we need to print either a text box or a drop down (for scales) // grades in item of type grade category or course are not directly editable. @@ -1132,7 +1066,7 @@ class grade_report_grader extends grade_report { } if (!$item->needsupdate) { - $context->actionmenu = $this->get_grade_action_menu($element); + $context->actionmenu = $this->get_cell_action_menu($element, 'gradeitem'); } $itemcell->text = $OUTPUT->render_from_template('gradereport_grader/cell', $context); @@ -1162,39 +1096,45 @@ class grade_report_grader extends grade_report { /** * Sets status icons for the grade. - * @param grade_grade $grade Grade + * @param array $element array with grade item info * * @return string status icons container HTML */ - public function set_grade_status_icons(grade_grade $grade) : string { + public function set_grade_status_icons(array $element) : string { global $OUTPUT; $attributes = ['class' => 'text-muted']; $statusicons = ''; - - if ($grade->is_hidden()) { + if ($element['object']->is_hidden()) { $statusicons .= $OUTPUT->pix_icon('i/show', $this->get_lang_string('hidden', 'grades'), 'moodle', $attributes); } - if ($grade->is_locked()) { + if ($element['object']->is_locked()) { $statusicons .= $OUTPUT->pix_icon('i/lock', $this->get_lang_string('locked', 'grades'), 'moodle', $attributes); } - if ($grade->is_overridden()) { - $statusicons .= $OUTPUT->pix_icon('i/overriden_grade', - $this->get_lang_string('overridden', 'grades'), 'moodle', $attributes); + if ($element['object'] instanceof grade_grade) { + $grade = $element['object']; + if ($grade->is_overridden()) { + $statusicons .= $OUTPUT->pix_icon('i/overriden_grade', + $this->get_lang_string('overridden', 'grades'), 'moodle', $attributes); + } + + if ($grade->is_excluded()) { + $statusicons .= $OUTPUT->pix_icon('i/excluded', $this->get_lang_string('excluded', 'grades'), + 'moodle', $attributes); + } } - if ($grade->is_excluded()) { - $statusicons .= $OUTPUT->pix_icon('i/excluded', $this->get_lang_string('excluded', 'grades'), - 'moodle', $attributes); + $class = 'grade_icons'; + if ($element['type'] == 'category') { + $class = 'category_grade_icons'; } - if ($statusicons) { - $statusicons = $OUTPUT->container($statusicons, 'grade_icons'); + $statusicons = $OUTPUT->container($statusicons, $class); } return $statusicons; } @@ -1236,10 +1176,15 @@ class grade_report_grader extends grade_report { * @param array $rows The Array of rows for the left part of the report * @param int $colspan The number of columns this cell has to span * @return array Array of rows for the left part of the report + * @deprecated since Moodle 4.2 - The row is not shown anymore - we have actions menu. + * @todo MDL-77307 This will be deleted in Moodle 4.6. */ public function get_left_icons_row($rows=array(), $colspan=1) { global $USER; + debugging('The function get_left_icons_row() is deprecated, please do not use it anymore.', + DEBUG_DEVELOPER); + if (!empty($USER->editing)) { $controlsrow = new html_table_row(); $controlsrow->attributes['class'] = 'controls'; @@ -1335,9 +1280,14 @@ class grade_report_grader extends grade_report { * Builds and return the row of icons when editing is on, for the right part of the grader report. * @param array $rows The Array of rows for the right part of the report * @return array Array of rows for the right part of the report + * @deprecated since Moodle 4.2 - The row is not shown anymore - we have actions menu. + * @todo MDL-77307 This will be deleted in Moodle 4.6. */ public function get_right_icons_row($rows=array()) { global $USER; + debugging('The function get_right_icons_row() is deprecated, please do not use it anymore.', + DEBUG_DEVELOPER); + if (!empty($USER->editing)) { $iconsrow = new html_table_row(); $iconsrow->attributes['class'] = 'controls'; @@ -1571,34 +1521,14 @@ class grade_report_grader extends grade_report { * @return string HTML */ protected function get_course_header($element) { - global $OUTPUT; + $actionmenu = $this->get_cell_action_menu($element, 'gradeitem'); - $icon = ''; - // If object is a category, display expand/contract icon. - if ($element['type'] == 'category') { - // Load language strings. - $strswitchminus = $this->get_lang_string('aggregatesonly', 'grades'); - $strswitchplus = $this->get_lang_string('gradesonly', 'grades'); - $strswitchwhole = $this->get_lang_string('fullmode', 'grades'); - - $url = new moodle_url($this->gpr->get_return_url(null, array('target' => $element['eid'], 'sesskey' => sesskey()))); - - if (in_array($element['object']->id, $this->collapsed['aggregatesonly'])) { - $url->param('action', 'switch_plus'); - $icon = $OUTPUT->action_icon($url, new pix_icon('t/switch_plus', ''), null, - ['title' => $strswitchplus, 'aria-label' => $strswitchplus]); - $showing = get_string('showingaggregatesonly', 'grades'); - } else if (in_array($element['object']->id, $this->collapsed['gradesonly'])) { - $url->param('action', 'switch_whole'); - $icon = $OUTPUT->action_icon($url, new pix_icon('t/switch_whole', ''), null, - ['title' => $strswitchwhole, 'aria-label' => $strswitchwhole]); - $showing = get_string('showinggradesonly', 'grades'); - } else { - $url->param('action', 'switch_minus'); - $icon = $OUTPUT->action_icon($url, new pix_icon('t/switch_minus', ''), null, - ['title' => $strswitchminus, 'aria-label' => $strswitchminus]); - $showing = get_string('showingfullmode', 'grades'); - } + if (in_array($element['object']->id, $this->collapsed['aggregatesonly'])) { + $showing = get_string('showingaggregatesonly', 'grades'); + } else if (in_array($element['object']->id, $this->collapsed['gradesonly'])) { + $showing = get_string('showinggradesonly', 'grades'); + } else { + $showing = get_string('showingfullmode', 'grades'); } $name = $element['object']->get_name(); @@ -1612,7 +1542,7 @@ class grade_report_grader extends grade_report { $courseheader .= html_writer::div($showing, 'sr-only', [ 'id' => $describedbyid ]); - $courseheader .= $icon; + $courseheader .= $actionmenu; return $courseheader; } @@ -1624,9 +1554,13 @@ class grade_report_grader extends grade_report { * * @param array $element * @return string HTML + * @deprecated since Moodle 4.2 - The row is not shown anymore - we have actions menu. + * @todo MDL-77307 This will be deleted in Moodle 4.6. */ protected function get_icons($element) { global $CFG, $USER, $OUTPUT; + debugging('The function get_icons() is deprecated, please do not use it anymore.', + DEBUG_DEVELOPER); if (empty($USER->editing)) { return '
'; @@ -1674,56 +1608,131 @@ class grade_report_grader extends grade_report { * Returns an action menu for the grade. * * @param array $element Array with cell info. + * @param string $mode Mode - gradeitem or user * @return string */ - public function get_grade_action_menu(array $element) : string { - global $OUTPUT, $USER; - - $editable = true; + public function get_cell_action_menu(array $element, string $mode): string { + global $OUTPUT, $USER, $CFG; $context = new stdClass(); - $editstrings = []; - $editstrings[] = $this->get_lang_string('editgrade', 'grades'); + if ($mode == 'gradeitem') { + $editable = true; + $editstrings = []; + $editstrings[] = $this->get_lang_string('editgrade', 'grades'); + $editstrings[] = $this->get_lang_string('itemsedit', 'grades'); + $editstrings[] = $this->get_lang_string('categoryedit', 'grades'); - $hidestrings = []; - $hidestrings[] = $this->get_lang_string('show'); - $hidestrings[] = $this->get_lang_string('hide'); + $editcalculationstrings = $this->get_lang_string('editcalculation', 'grades'); - $lockstrings = []; - $lockstrings[] = $this->get_lang_string('unlock', 'grades'); - $lockstrings[] = $this->get_lang_string('lock', 'grades'); + $hidestrings = []; + $hidestrings[] = $this->get_lang_string('show'); + $hidestrings[] = $this->get_lang_string('hide'); - $gradeanalysisstring = $this->get_lang_string('gradeanalysis', 'grades'); + $lockstrings = []; + $lockstrings[] = $this->get_lang_string('unlock', 'grades'); + $lockstrings[] = $this->get_lang_string('lock', 'grades'); - if ($element['type'] == 'grade') { - $context->isgrade = true; - $item = $element['object']->grade_item; - if ($item->is_course_item() || $item->is_category_item()) { - $editable = $this->overridecat; - } + $gradeanalysisstring = $this->get_lang_string('gradeanalysis', 'grades'); - if (!empty($USER->editing)) { - if ($editable) { - $context->editurl = $this->gtree->get_edit_link($element, $this->gpr, $editstrings); + if ($element['type'] == 'grade') { + $item = $element['object']->grade_item; + if ($item->is_course_item() || $item->is_category_item()) { + $editable = $this->overridecat; } - if (has_capability('moodle/grade:manage', $this->context)) { + if (!empty($USER->editing)) { + if ($editable) { + $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); } + + $context->gradeanalysisurl = $this->gtree->get_grade_analysis_link($element['object'], $gradeanalysisstring); + } else if (($element['type'] == 'item') || + ($element['type'] == 'categoryitem') || + ($element['type'] == 'courseitem')) { + + if ($element['type'] == 'item') { + foreach ($this->get_report_links($this->context, $this->courseid, $element, $this->gpr, $mode) + as $count => $reportlink) { + $temp = 'reporturl' . $count; + $context->$temp = $reportlink; + } + $context->advancedgradingurl = $this->gtree->get_advanced_grading_link($element, $this->gpr); + } + + if (!empty($USER->editing)) { + $context->divider = true; + + if ($element['type'] == 'item') { + $context->editurl = $this->gtree->get_edit_link($element, $this->gpr, $editstrings); + } + + $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); + } + $context->lockurl = $this->gtree->get_locking_link($element, $this->gpr, $lockstrings); + } + } else if ($element['type'] == 'category') { + $categoryid = $element['object']->id; + + // Load language strings. + $strswitchminus = $this->get_lang_string('aggregatesonly', 'grades'); + $strswitchplus = $this->get_lang_string('gradesonly', 'grades'); + $strswitchwhole = $this->get_lang_string('fullmode', 'grades'); + + $url = new moodle_url($this->gpr->get_return_url(null, + ['target' => $element['eid'], 'sesskey' => sesskey()])); + + $gradesonly = false; + $aggregatesonly = false; + $fullmode = false; + if (in_array($categoryid, $this->collapsed['gradesonly'])) { + $gradesonly = true; + } else if (in_array($categoryid, $this->collapsed['aggregatesonly'])) { + $aggregatesonly = true; + } else { + $fullmode = true; + } + $context->gradesonlyurl = + $this->gtree->get_category_view_mode_link($url, $strswitchplus, 'switch_plus', $gradesonly); + $context->aggregatesonlyurl = + $this->gtree->get_category_view_mode_link($url, $strswitchminus, 'switch_minus', $aggregatesonly); + $context->fullmodeurl = + $this->gtree->get_category_view_mode_link($url, $strswitchwhole, 'switch_whole', $fullmode); + + if (!empty($USER->editing)) { + $context->divider = 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); + } + } - $context->gradeanalysisurl = $this->gtree->get_grade_analysis_link($element['object'], $gradeanalysisstring); + $context->dataid = $element['object']->id; + } else if ($mode == 'user') { + foreach ($this->get_report_links($this->context, $this->courseid, $element, $this->gpr, $mode) + as $count => $reportlink) { + $temp = 'reporturl' . $count; + $context->$temp = $reportlink; + } + $context->dataid = $element['userid']; } - if (!empty($USER->editing) || isset($context->gradeanalysisurl)) { - return $OUTPUT->render_from_template('gradereport_grader/grademenu', $context); + if (!empty($USER->editing) || isset($context->gradeanalysisurl) || isset($context->gradesonlyurl) + || isset($context->aggregatesonlyurl) || isset($context->fullmodeurl) || isset($context->reporturl0)) { + return $OUTPUT->render_from_template('gradereport_grader/cellmenu', $context); } return ''; } - /** * Given a category element returns collapsing +/- icon if available * @@ -1910,6 +1919,11 @@ class grade_report_grader extends grade_report { static::set_collapsed_preferences($courseid, $collapsed); } + $key = array_search($targetid, $collapsed['aggregatesonly']); + if ($key !== false) { + unset($collapsed['aggregatesonly'][$key]); + static::set_collapsed_preferences($courseid, $collapsed); + } break; default: break; diff --git a/grade/report/grader/styles.css b/grade/report/grader/styles.css index dfb8217afe1..c8e1435eed9 100644 --- a/grade/report/grader/styles.css +++ b/grade/report/grader/styles.css @@ -65,6 +65,10 @@ color: #ca3120; } +.path-grade-report-grader .grade_icons { + text-align: center; +} + /** * All the floating divs. */ @@ -91,13 +95,21 @@ * The user cells. */ .path-grade-report-grader .gradeparent .user.cell { - min-width: 200px; - width: 200px; + min-width: 250px; + width: 250px; white-space: normal; - vertical-align: top; + vertical-align: middle; height: 100px; } +.path-grade-report-grader .gradeparent .highlightable.cell { + height: 80px; + text-align: center; + vertical-align: top; + padding-top: 20px; + min-width: 150px; +} + .path-grade-report-grader .gradeparent .gradecell { vertical-align: top; padding-top: 20px; @@ -117,7 +129,7 @@ overflow: hidden; text-overflow: ellipsis; max-width: 200px; - vertical-align: bottom; + vertical-align: middle; } /** diff --git a/grade/report/grader/templates/grademenu.mustache b/grade/report/grader/templates/cellmenu.mustache similarity index 50% rename from grade/report/grader/templates/grademenu.mustache rename to grade/report/grader/templates/cellmenu.mustache index 4ffd8decc0d..dec041c4a37 100644 --- a/grade/report/grader/templates/grademenu.mustache +++ b/grade/report/grader/templates/cellmenu.mustache @@ -1,29 +1,35 @@ {{! 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 block_timeline/nav-day-filter - This template renders the day range selector for the timeline view. + @template gradereport_grader/cellmenu + + This template renders action menu for a given cell. Example context (json): { "editurl": "Edit grade", - "hideurl": "Hide" + "hideurl": "Hide", + "reporturl0": "Single view for this user", + "reporturl1": "User report" } }}