$courseid = required_param('id'); // course id
$report = optional_param('report', 'user', PARAM_FILE); // course id
$edit = optional_param('edit', -1, PARAM_BOOL); // sticky editting mode
- $feedback = optional_param('feedback', -1, PARAM_BOOL); // sticky feedback mode
/// Make sure they can even access this course
$USER->gradeediting = 0;
}
- // params for the turn editting on and feedback buttons
+ // params for the turn editting on
$options['id'] = $courseid;
$options['report'] = $report;
--- /dev/null
+<?php // $Id$
+/**
+ * File in which the grader_report class is defined.
+ * @package gradebook
+ */
+
+define('GRADER_REPORT_AGGREGATION_POSITION_LEFT', 0);
+define('GRADER_REPORT_AGGREGATION_POSITION_RIGHT', 1);
+define('GRADER_REPORT_AGGREGATION_VIEW_FULL', 0);
+define('GRADER_REPORT_AGGREGATION_VIEW_COMPACT', 1);
+define('GRADER_REPORT_GRADE_DISPLAY_TYPE_RAW', 0);
+define('GRADER_REPORT_GRADE_DISPLAY_TYPE_PERCENTAGE', 1);
+define('GRADER_REPORT_FEEDBACK_FORMAT_TEXT', 0);
+define('GRADER_REPORT_FEEDBACK_FORMAT_HTML', 1);
+
+require_once($CFG->libdir.'/tablelib.php');
+require_once($CFG->libdir.'/gradelib.php');
+require_once($CFG->dirroot.'/grade/report/lib.php');
+
+/**
+ * Class providing an API for the grader report building and displaying.
+ * @package gradebook
+ */
+class grade_report_grader {
+ /**
+ * The courseid.
+ * @var int $courseid
+ */
+ var $courseid;
+
+ /**
+ * The context.
+ * @var int $context
+ */
+ var $context;
+
+ /**
+ * The grade_tree object.
+ * @var object $gtree
+ */
+ var $gtree;
+
+ /**
+ * The final grades.
+ * @var array $finalgrades
+ */
+ var $finalgrades;
+
+ /**
+ * The grade items.
+ * @var array $items
+ */
+ var $items;
+
+ /**
+ * Array of errors for bulk grades updating.
+ * @var array $gradeserror
+ */
+ var $gradeserror = array();
+
+//// USER PREFERENCES
+
+ /**
+ * Number of users on a page.
+ * @var int $perpage
+ */
+ var $studentsperpage;
+
+ /**
+ * Number of digits after the decimal point.
+ * @var int $decimalspoints
+ */
+ var $decimalspoints;
+
+ /**
+ * Whether or not to display the grandtotals row.
+ * @var bool $showgrandtotals
+ */
+ var $showgrandtotals;
+
+ /**
+ * Whether or not to display group selector, total row and other group-related elements.
+ * @var bool $showgroups
+ */
+ var $showgroups;
+
+ /**
+ * The position of the Aggregation column in relation to the raw grade items.
+ * @var int $aggregation_position
+ */
+ var $aggregation_position;
+
+ /**
+ * Whether or not to display a row of scales/ranges for each grade_item.
+ * @var bool $showscales
+ */
+ var $showscales;
+
+ /**
+ * Whether or not to use quickgrading.
+ * @var bool $quickgrading
+ */
+ var $quickgrading;
+
+ /**
+ * Whether or not to use quickfeedback.
+ * @var bool $quickfeedback
+ */
+ var $quickfeedback;
+
+//// SQL-RELATED
+
+ /**
+ * The roles for this report.
+ * @var string $gradebookroles
+ */
+ var $gradebookroles;
+
+ /**
+ * base url for sorting by first/last name.
+ * @var string $baseurl
+ */
+ var $baseurl;
+
+ /**
+ * base url for paging.
+ * @var string $pbarurl
+ */
+ var $pbarurl;
+
+ /**
+ * Current page (for paging).
+ * @var int $page
+ */
+ var $page;
+
+ /**
+ * The id of the grade_item by which this report will be sorted.
+ * @var int $sortitemid
+ */
+ var $sortitemid;
+
+ /**
+ * Sortorder used in the SQL selections.
+ * @var int $sortorder
+ */
+ var $sortorder;
+
+ /**
+ * An SQL fragment affecting the search for users.
+ * @var string $userselect
+ */
+ var $userselect;
+
+//// GROUP VARIABLES (including SQL)
+
+ /**
+ * The current group being displayed.
+ * @var int $currentgroup
+ */
+ var $currentgroup;
+
+ /**
+ * A HTML select element used to select the current group.
+ * @var string $group_selector
+ */
+ var $group_selector;
+
+ /**
+ * An SQL fragment used to add linking information to the group tables.
+ * @var string $groupsql
+ */
+ var $groupsql;
+
+ /**
+ * An SQL constraint to append to the queries used by this object to build the report.
+ * @var string $groupwheresql
+ */
+ var $groupwheresql;
+
+
+
+ /**
+ * Constructor. Sets local copies of user preferences and initialises grade_tree.
+ * @param int $courseid
+ */
+ function grade_report_grader($courseid, $context, $page=null, $sortitemid=null) {
+ global $CFG;
+
+ $this->courseid = $courseid;
+ $this->context = $context;
+ $this->page = $page;
+ $this->sortitemid = $sortitemid;
+
+ // roles to be displayed in the gradebook
+ $this->gradebookroles = $CFG->gradebookroles;
+
+ // User preferences
+ $this->studentsperpage = get_user_preferences('grade_report_studentsperpage',
+ $CFG->grade_report_studentsperpage);
+ $this->decimalpoints = get_user_preferences('grade_report_decimalpoints',
+ $CFG->grade_report_decimalpoints);
+ $this->showgrandtotals = get_user_preferences('grade_report_showgrandtotals',
+ $CFG->grade_report_showgrandtotals);
+ $this->showgroups = get_user_preferences('grade_report_showgroups',
+ $CFG->grade_report_showgroups);
+ $this->aggregation_position = get_user_preferences('grade_report_aggregationposition',
+ $CFG->grade_report_aggregationposition);
+ $this->showscales = get_user_preferences('grade_report_showscales',
+ $CFG->grade_report_showscales);
+ $this->quickgrading = get_user_preferences('grade_report_quickgrading',
+ $CFG->grade_report_quickgrading);
+ $this->quickfeedback = get_user_preferences('grade_report_quickfeedback',
+ $CFG->grade_report_quickfeedback);
+
+ // Grab the grade_tree for this course
+ $this->gtree = new grade_tree($this->courseid, true, false, $this->aggregation_position);
+
+ // base url for sorting by first/last name
+ $this->baseurl = 'report.php?id='.$this->courseid.'&perpage='.$this->studentsperpage.'&report=grader&page='.$this->page;
+ //
+ $this->pbarurl = 'report.php?id='.$this->courseid.'&perpage='.$this->studentsperpage.'&report=grader&';
+
+ if ($this->showgroups) {
+ $this->setup_groups();
+ }
+
+ $this->setup_sortitemid();
+ }
+
+ /**
+ * Uses set_user_preferences() to update the value of a user preference.
+ * Also updates the object's corresponding variable.
+ * @param string $pref_name The name of the preference.
+ * @param mixed $pref_value The value of the preference.
+ * @return bool Success or failure.
+ * TODO print visual feedback
+ */
+ function set_user_pref($pref_name, $pref_value) {
+ if ($result = set_user_preferences(array($pref_name => $pref_value))) {
+ $this->$pref_name = $pref_value;
+ }
+ return $result;
+ }
+
+ /**
+ * Processes the data sent by the form (grades and feedbacks).
+ * @var array $data
+ * @return bool Success or Failure (array of errors).
+ */
+ function process_data($data) {
+ // always initialize all arrays
+ $queue = array();
+
+ foreach ($data as $varname => $postedvalue) {
+ // this is a bit tricky - we have to first load all grades into memory,
+ // check if changed and only then start updating the final grades because
+ // columns might depend one on another - the result would be overriden calculated and category grades
+
+ $needsupdate = false;
+ $note = false; // TODO implement note??
+
+ // skip, not a grade nor feedback
+ $data_type = '';
+ if (strstr($varname, 'grade')) {
+ $data_type = 'grade';
+ } elseif (strstr($varname, 'feedback')) {
+ $data_type = 'feedback';
+ } else {
+ continue;
+ }
+
+ $gradeinfo = explode("_", $varname);
+
+ $userid = clean_param($gradeinfo[1], PARAM_INT);
+ $itemid = clean_param($gradeinfo[2], PARAM_INT);
+
+ if (!$grade_item = grade_item::fetch(array('id'=>$itemid, 'courseid'=>$this->courseid))) { // we must verify course id here!
+ error('Incorrect grade item id');
+ }
+
+ // Pre-process grade
+ if ($data_type == 'grade') {
+
+ if ($grade_item->gradetype == GRADE_TYPE_SCALE) {
+ if ($postedvalue == -1) { // -1 means no grade
+ $finalgrade = null;
+ } else {
+ $finalgrade = (float)$postedvalue;
+ }
+ } else {
+ if ($postedvalue == '') { // empty string means no grade
+ $finalgrade = null;
+ } else {
+ $finalgrade = format_grade($postedvalue);
+ }
+ }
+
+ if (!is_null($finalgrade) and ($finalgrade < $grade_item->grademin or $finalgrade > $grade_item->grademax)) {
+ $this->gradeserror[$grade_item->id][$userid] = 'outofrange'; //TODO: localize
+ // another possiblity is to use bounded number instead
+ continue;
+ }
+ }
+
+ // Get the grade object to compare old value with new value
+ if ($grade = grade_grades::fetch(array('userid'=>$userid, 'itemid'=>$grade_item->id))) {
+ if ($data_type == 'feedback') {
+ $finalgrade = false;
+ $text = $grade->load_text();
+ if ($text != s($postedvalue)) {
+ $feedback = s($postedvalue);
+ $feedbackformat = GRADER_REPORT_FEEDBACK_FORMAT_TEXT;
+ $needsupdate = true;
+ }
+ } elseif ($data_type == 'grade') {
+ $feedback = false;
+ $feedbackformat = false;
+ if (!is_null($grade->finalgrade)) {
+ $grade->finalgrade = (float)$grade->finalgrade;
+ }
+ if ($grade->finalgrade === $finalgrade) {
+ $needsupdate = true;
+ }
+ }
+
+ }
+
+ // we must not update all grades, only changed ones - we do not want to mark everything as overriden
+ if ($needsupdate) {
+ $gradedata = new object();
+ $gradedata->grade_item = $grade_item;
+ $gradedata->userid = $userid;
+ $gradedata->note = $note;
+ $gradedata->finalgrade = $finalgrade;
+ $gradedata->feedback = $feedback;
+ $gradedata->feedbackformat = $feedbackformat;
+
+ $queue[] = $gradedata;
+ }
+ }
+
+ // now we update the new final grade for each changed grade
+ foreach ($queue as $gradedata) {
+ $gradedata->grade_item->update_final_grade($gradedata->userid, $gradedata->finalgrade, 'gradebook',
+ $gradedata->note, $gradedata->feedback, $gradedata->feedbackformat);
+ }
+
+ return true;
+ }
+
+ /**
+ * Sets up this object's group variables, mainly to restrict the selection of users to display.
+ */
+ function setup_groups() {
+ global $CFG;
+
+ /// find out current groups mode
+ $course = get_record('course', 'id', $this->courseid);
+ $groupmode = $course->groupmode;
+ ob_start();
+ $this->currentgroup = setup_and_print_groups($course, $groupmode, $this->baseurl);
+ $this->group_selector = ob_get_clean();
+
+ // update paging after group
+ $this->baseurl .= 'group='.$this->currentgroup.'&';
+ $this->pbarurl .= 'group='.$this->currentgroup.'&';
+
+ if ($this->currentgroup) {
+ $this->groupsql = " LEFT JOIN {$CFG->prefix}groups_members gm ON gm.userid = u.id ";
+ $this->groupwheresql = " AND gm.groupid = $this->currentgroup ";
+ }
+ }
+
+ /**
+ * 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.
+ */
+ function setup_sortitemid() {
+ if ($this->sortitemid) {
+ if (!isset($SESSION->gradeuserreport->sort)) {
+ $this->sortorder = $SESSION->gradeuserreport->sort = 'ASC';
+ } else {
+ // this is the first sort, i.e. by last name
+ if (!isset($SESSION->gradeuserreport->sortitemid)) {
+ $this->sortorder = $SESSION->gradeuserreport->sort = 'ASC';
+ } else if ($SESSION->gradeuserreport->sortitemid == $this->sortitemid) {
+ // same as last sort
+ if ($SESSION->gradeuserreport->sort == 'ASC') {
+ $this->sortorder = $SESSION->gradeuserreport->sort = 'DESC';
+ } else {
+ $this->sortorder = $SESSION->gradeuserreport->sort = 'ASC';
+ }
+ } else {
+ $this->sortorder = $SESSION->gradeuserreport->sort = 'ASC';
+ }
+ }
+ $SESSION->gradeuserreport->sortitemid = $this->sortitemid;
+ } else {
+ // not requesting sort, use last setting (for paging)
+
+ if (isset($SESSION->gradeuserreport->sortitemid)) {
+ $this->sortitemid = $SESSION->gradeuserreport->sortitemid;
+ }
+ if (isset($SESSION->gradeuserreport->sort)) {
+ $this->sortorder = $SESSION->gradeuserreport->sort;
+ } else {
+ $this->sortorder = 'ASC';
+ }
+ }
+ }
+
+ /**
+ * Processes a single action against a category, grade_item or grade.
+ * @param string $target Sortorder
+ * @param string $action Which action to take (edit, delete etc...)
+ * @return
+ * TODO Update this, it's quite old and needs a major makeover
+ */
+ function process_action($target, $action) {
+ $element = $this->gtree->locate_element($target);
+
+ switch ($action) {
+ case 'edit':
+ break;
+ case 'delete':
+ if ($confirm == 1) { // Perform the deletion
+ //TODO: add proper delete support for grade items and categories
+ //$element['object']->delete();
+ // Print result message
+
+ } else { // Print confirmation dialog
+ $eid = $element['eid'];
+ $strdeletecheckfull = get_string('deletecheck', '', $element['object']->get_name());
+ $linkyes = "category.php?target=$eid&action=delete&confirm=1$this->gtree->commonvars";
+ $linkno = "category.php?$this->gtree->commonvars";
+ notice_yesno($strdeletecheckfull, $linkyes, $linkno);
+ }
+ break;
+
+ case 'hide':
+ // TODO Implement calendar for selection of a date to hide element until
+ $element['object']->set_hidden(1);
+ $this->gtree = new grade_tree($this->courseid);
+ break;
+ case 'show':
+ $element['object']->set_hidden(0);
+ $this->gtree = new grade_tree($this->courseid);
+ break;
+ case 'lock':
+ // TODO Implement calendar for selection of a date to lock element after
+ if (!$element['object']->set_locked(1)) {
+ debugging("Could not update the element's locked state!");
+ }
+ $this->gtree = new grade_tree($this->courseid);
+ break;
+ case 'unlock':
+ if (!$element['object']->set_locked(0)) {
+ debugging("Could not update the element's locked state!");
+ }
+ $this->gtree = new grade_tree($this->courseid);
+ break;
+ default:
+ break;
+ }
+
+ }
+
+ /**
+ * pulls out the userids of the users to be display, and sort them
+ * the right outer join is needed because potentially, it is possible not
+ * to have the corresponding entry in grade_grades table for some users
+ * this is check for user roles because there could be some users with grades
+ * but not supposed to be displayed
+ */
+ function load_users() {
+ global $CFG;
+
+ if (is_numeric($this->sortitemid)) {
+ $sql = "SELECT u.id, u.firstname, u.lastname
+ FROM {$CFG->prefix}grade_grades g RIGHT OUTER JOIN
+ {$CFG->prefix}user u ON (u.id = g.userid AND g.itemid = $this->sortitemid)
+ LEFT JOIN {$CFG->prefix}role_assignments ra ON u.id = ra.userid
+ $this->groupsql
+ WHERE ra.roleid in ($this->gradebookroles)
+ $this->groupwheresql
+ AND ra.contextid ".get_related_contexts_string($this->context)."
+ ORDER BY g.finalgrade $this->sortorder";
+ $this->users = get_records_sql($sql, $this->studentsperpage * $this->page, $this->studentsperpage);
+ } else {
+ // default sort
+ // get users sorted by lastname
+ $this->users = get_role_users(@implode(',', $CFG->gradebookroles), $this->context, false,
+ 'u.id, u.firstname, u.lastname', 'u.'.$this->sortitemid .' '. $this->sortorder,
+ false, $this->page * $this->studentsperpage, $this->studentsperpage, $this->currentgroup);
+ // need to cut users down by groups
+
+ }
+
+ if (empty($this->users)) {
+ $this->userselect = '';
+ $this->users = array();
+ } else {
+ $this->userselect = 'AND g.userid in ('.implode(',', array_keys($this->users)).')';
+ }
+
+ return $this->users;
+ }
+
+ /**
+ * Fetches and returns a count of all the users that will be shows on this page.
+ * @return int Count of users
+ */
+ function get_numusers() {
+ global $CFG;
+ $countsql = "SELECT COUNT(DISTINCT u.id)
+ FROM {$CFG->prefix}grade_grades g RIGHT OUTER JOIN
+ {$CFG->prefix}user u ON (u.id = g.userid AND g.itemid = $this->sortitemid)
+ LEFT JOIN {$CFG->prefix}role_assignments ra ON u.id = ra.userid
+ $this->groupsql
+ WHERE ra.roleid in ($this->gradebookroles)
+ $this->groupwheresql
+ AND ra.contextid ".get_related_contexts_string($this->context);
+ return count_records_sql($countsql);
+ }
+
+ /**
+ * we supply the userids in this query, and get all the grades
+ * pulls out all the grades, this does not need to worry about paging
+ */
+ function load_final_grades() {
+ global $CFG;
+
+ $sql = "SELECT g.id, g.itemid, g.userid, g.finalgrade, g.hidden, g.locked, g.locktime, g.overridden, gt.feedback
+ FROM {$CFG->prefix}grade_items gi,
+ {$CFG->prefix}grade_grades g
+ LEFT JOIN {$CFG->prefix}grade_grades_text gt ON g.id = gt.gradeid
+ WHERE g.itemid = gi.id
+ AND gi.courseid = $this->courseid $this->userselect";
+
+ if ($grades = get_records_sql($sql)) {
+ foreach ($grades as $grade) {
+ $this->finalgrades[$grade->userid][$grade->itemid] = $grade;
+ }
+ }
+ }
+
+ /**
+ * Builds and returns a div with on/off toggles.
+ * @return string HTML code
+ */
+ function get_toggles_html() {
+ global $USER;
+ $html = '<div id="grade-report-toggles">';
+ if ($USER->gradeediting) {
+ $html .= $this->print_toggle('eyecons', true);
+ $html .= $this->print_toggle('locks', true);
+ $html .= $this->print_toggle('calculations', true);
+ }
+
+ $html .= $this->print_toggle('grandtotals', true);
+ $html .= $this->print_toggle('groups', true);
+ $html .= $this->print_toggle('scales', true);
+ $html .= '</div>';
+ return $html;
+ }
+
+ /**
+ * Shortcut function for printing the grader report toggles.
+ * @param string $type The type of toggle
+ * @param bool $return Whether to return the HTML string rather than printing it
+ * @return void
+ */
+ function print_toggle($type, $return=false) {
+ global $CFG;
+
+ $icons = array('eyecons' => 'hide',
+ 'calculations' => 'calc',
+ 'locks' => 'lock',
+ 'grandtotals' => 'sigma');
+
+ $pref_name = 'grade_report_show' . $type;
+ $show_pref = get_user_preferences($pref_name, $CFG->$pref_name);
+
+ $strshow = get_string('show' . $type, 'grades');
+ $strhide = get_string('hide' . $type, 'grades');
+
+ $show_hide = 'show';
+ $toggle_action = 1;
+
+ if ($show_pref) {
+ $show_hide = 'hide';
+ $toggle_action = 0;
+ }
+
+ if (array_key_exists($type, $icons)) {
+ $image_name = $icons[$type];
+ } else {
+ $image_name = $type;
+ }
+
+ $string = ${'str' . $show_hide};
+
+ $img = '<img src="'.$CFG->pixpath.'/t/'.$image_name.'.gif" class="iconsmall" alt="'
+ .$string.'" title="'.$string.'" />'. "\n";
+
+ $retval = '<div class="gradertoggle">' . $img . '<a href="' . $this->baseurl . "&toggle=$toggle_action&toggle_type=$type\">"
+ . $string . '</a></div>';
+
+ if ($return) {
+ return $retval;
+ } else {
+ echo $retval;
+ }
+ }
+
+ /**
+ * Builds and returns the HTML code for the headers.
+ * @return string $headerhtml
+ */
+ function get_headerhtml() {
+ global $CFG, $USER;
+
+ $strsortasc = get_string('sortasc', 'grades');
+ $strsortdesc = get_string('sortdesc', 'grades');
+ if ($this->sortitemid === 'lastname') {
+ if ($this->sortorder == 'ASC') {
+ $lastarrow = print_arrow('up', $strsortasc, true);
+ } else {
+ $lastarrow = print_arrow('down', $strsortdesc, true);
+ }
+ } else {
+ $lastarrow = '';
+ }
+
+ if ($this->sortitemid === 'firstname') {
+ if ($this->sortorder == 'ASC') {
+ $firstarrow = print_arrow('up', $strsortasc, true);
+ } else {
+ $firstarrow = print_arrow('down', $strsortdesc, true);
+ }
+ } else {
+ $firstarrow = '';
+ }
+ // Prepare Table Headers
+ $headerhtml = '';
+
+ $numrows = count($this->gtree->levels);
+
+ foreach ($this->gtree->levels as $key=>$row) {
+ if ($key == 0) {
+ // do not diplay course grade category
+ // continue;
+ }
+
+ $headerhtml .= '<tr class="heading">';
+
+ if ($key == $numrows - 1) {
+ $headerhtml .= '<th class="user"><a href="'.$this->baseurl.'&sortitemid=firstname">Firstname</a> ' //TODO: localize
+ . $firstarrow. '/ <a href="'.$this->baseurl.'&sortitemid=lastname">Lastname </a>'. $lastarrow .'</th>';
+ } else {
+ $headerhtml .= '<td class="topleft"> </td>';
+ }
+
+ foreach ($row as $element) {
+ $eid = $element['eid'];
+ $object = $element['object'];
+ $type = $element['type'];
+
+ if (!empty($element['colspan'])) {
+ $colspan = 'colspan="'.$element['colspan'].'"';
+ } else {
+ $colspan = '';
+ }
+
+ if (!empty($element['depth'])) {
+ $catlevel = ' catlevel'.$element['depth'];
+ } else {
+ $catlevel = '';
+ }
+
+
+ if ($type == 'filler' or $type == 'fillerfirst' or $type == 'fillerlast') {
+ $headerhtml .= '<td class="'.$type.$catlevel.'" '.$colspan.'> </td>';
+ } else if ($type == 'category') {
+ $headerhtml .= '<td class="category'.$catlevel.'" '.$colspan.'>'.$element['object']->get_name();
+
+ // Print icons
+ if ($USER->gradeediting) {
+ $headerhtml .= $this->get_icons($element);
+ }
+
+ $headerhtml .= '</td>';
+ } else {
+ if ($element['object']->id == $this->sortitemid) {
+ if ($this->sortorder == 'ASC') {
+ $arrow = print_arrow('up', $strsortasc, true);
+ } else {
+ $arrow = print_arrow('down', $strsortdesc, true);
+ }
+ } else {
+ $arrow = '';
+ }
+
+ $dimmed = '';
+ if ($element['object']->is_hidden()) {
+ $dimmed = ' dimmed_text ';
+ }
+
+ if ($object->itemtype == 'mod') {
+ $icon = '<img src="'.$CFG->modpixpath.'/'.$object->itemmodule.'/icon.gif" class="icon" alt="'
+ .get_string('modulename', $object->itemmodule).'"/>';
+ } else if ($object->itemtype == 'manual') {
+ //TODO: add manual grading icon
+ $icon = '<img src="'.$CFG->pixpath.'/t/edit.gif" class="icon" alt="'.get_string('manualgrade', 'grades')
+ .'"/>';
+ }
+
+
+ $headerhtml .= '<th class="'.$type.$catlevel.$dimmed.'"><a href="'.$this->baseurl.'&sortitemid='
+ . $element['object']->id .'">'. $element['object']->get_name()
+ . '</a>' . $arrow;
+
+ $headerhtml .= $this->get_icons($element) . '</th>';
+
+ $this->items[$element['object']->sortorder] =& $element['object'];
+ }
+
+ }
+
+ $headerhtml .= '</tr>';
+ }
+ return $headerhtml;
+ }
+
+ /**
+ * Builds and return the HTML rows of the table (grades headed by student).
+ * @return string HTML
+ */
+ function get_studentshtml() {
+ global $CFG, $USER;
+ $studentshtml = '';
+ $strfeedback = get_string("feedback");
+
+ foreach ($this->users as $userid => $user) {
+ // Student name and link
+ $studentshtml .= '<tr><th class="user"><a href="' . $CFG->wwwroot . '/user/view.php?id='
+ . $user->id . '">' . fullname($user) . '</a></th>';
+ foreach ($this->items as $item) {
+
+ if (isset($this->finalgrades[$userid][$item->id])) {
+ $gradeval = $this->finalgrades[$userid][$item->id]->finalgrade;
+ $grade = new grade_grades($this->finalgrades[$userid][$item->id], false);
+ $grade->feedback = $this->finalgrades[$userid][$item->id]->feedback;
+
+ } else {
+ $gradeval = null;
+ $grade = new grade_grades(array('userid' => $userid, 'itemid' => $item->id), false);
+ $grade->feedback = '';
+ }
+
+ if ($grade->is_overridden()) {
+ $studentshtml .= '<td class="overridden">';
+ } else {
+ $studentshtml .= '<td>';
+ }
+
+ // emulate grade element
+ $grade->courseid = $this->courseid;
+ $grade->grade_item = $item; // this may speedup is_hidden() and other grade_grades methods
+ $element = array ('eid'=>'g'.$grade->id, 'object'=>$grade, 'type'=>'grade');
+
+ // Do not show any icons if no grade (no record in DB to match)
+ if (!empty($grade->id)) {
+ $studentshtml .= $this->get_icons($element);
+ }
+
+ // if in editting 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
+ if ($USER->gradeediting) {
+ // We need to retrieve each grade_grade object from DB in order to
+ // know if they are hidden/locked
+
+ if ($item->scaleid) {
+ if ($scale = get_record('scale', 'id', $item->scaleid)) {
+ $scales = explode(",", $scale->scale);
+ // reindex because scale is off 1
+ $i = 0;
+ foreach ($scales as $scaleoption) {
+ $i++;
+ $scaleopt[$i] = $scaleoption;
+ }
+
+ if ($this->quickgrading) {
+ $studentshtml .= choose_from_menu($scaleopt, 'grade_'.$userid.'_'.$item->id,
+ $gradeval, get_string('nograde'), '', -1, true);
+ } elseif ($scale = get_record('scale', 'id', $item->scaleid)) {
+ $scales = explode(",", $scale->scale);
+
+ // invalid grade if gradeval < 1
+ if ((int) $gradeval < 1) {
+ $studentshtml .= '-';
+ } else {
+ $studentshtml .= $scales[$gradeval-1];
+ }
+ } else {
+ // no such scale, throw error?
+ }
+ }
+ } else {
+ if ($this->quickgrading) {
+ $studentshtml .= '<input size="6" type="text" name="grade_'.$userid.'_'
+ .$item->id.'" value="'.get_grade_clean($gradeval).'"/>';
+ } else {
+ $studentshtml .= get_grade_clean($gradeval);
+ }
+ }
+
+
+ // If quickfeedback is on, print an input element
+ if ($this->quickfeedback) {
+ if ($this->quickgrading) {
+ $studentshtml .= '<br />';
+ }
+ $studentshtml .= '<input size="6" type="text" name="feedback_'.$userid.'_'.$item->id.'" value="'
+ . s($grade->feedback) . '"/>';
+ }
+
+ $studentshtml .= '<div class="grade_icons">' . $this->get_icons($element, array('edit')) . '</div>';
+ } else {
+ // If feedback present, surround grade with feedback tooltip
+ if (!empty($grade->feedback)) {
+ $studentshtml .= '<span onmouseover="return overlib(\''.$grade->feedback.'\', CAPTION, \''
+ . $strfeedback.'\');" onmouseout="return nd();">';
+ }
+
+ // finalgrades[$userid][$itemid] could be null because of the outer join
+ // in this case it's different than a 0
+ if ($item->scaleid) {
+ if ($scale = get_record('scale', 'id', $item->scaleid)) {
+ $scales = explode(",", $scale->scale);
+
+ // invalid grade if gradeval < 1
+ if ((int) $gradeval < 1) {
+ $studentshtml .= '-';
+ } else {
+ $studentshtml .= $scales[$gradeval-1];
+ }
+ } else {
+ // no such scale, throw error?
+ }
+ } else {
+ if (is_null($gradeval)) {
+ $studentshtml .= '-';
+ } else {
+ $studentshtml .= get_grade_clean($gradeval);
+ }
+ }
+ if (!empty($grade->feedback)) {
+ $studentshtml .= '</span>';
+ }
+ }
+
+ if (!empty($this->gradeserror[$item->id][$userid])) {
+ $studentshtml .= $this->gradeserror[$item->id][$userid];
+ }
+
+ $studentshtml .= '</td>' . "\n";
+ }
+ $studentshtml .= '</tr>';
+ }
+ return $studentshtml;
+ }
+
+ /**
+ * Builds and return the HTML rows of the table (grades headed by student).
+ * @return string HTML
+ */
+ function get_groupsumhtml() {
+ global $CFG;
+
+ $groupsumhtml = '';
+
+ if ($this->currentgroup && $this->showgroups) {
+
+ /** SQL for finding group sum */
+ $SQL = "SELECT g.itemid, SUM(g.finalgrade) as sum
+ FROM {$CFG->prefix}grade_items gi LEFT JOIN
+ {$CFG->prefix}grade_grades g ON gi.id = g.itemid RIGHT OUTER JOIN
+ {$CFG->prefix}user u ON u.id = g.userid LEFT JOIN
+ {$CFG->prefix}role_assignments ra ON u.id = ra.userid
+ $this->groupsql
+ WHERE gi.courseid = $this->courseid
+ $this->groupwheresql
+ AND ra.roleid in ($this->gradebookroles)
+ AND ra.contextid ".get_related_contexts_string($this->context)."
+ GROUP BY g.itemid";
+
+ $groupsum = array();
+ $sums = get_records_sql($SQL);
+ foreach ($sums as $itemid => $csum) {
+ $groupsum[$itemid] = $csum;
+ }
+
+ $groupsumhtml = '<tr><th>Group total</th>';
+ foreach ($this->items as $item) {
+ if (!isset($groupsum[$item->id])) {
+ $groupsumhtml .= '<td>-</td>';
+ } else {
+ $sum = $groupsum[$item->id];
+ $groupsumhtml .= '<td>'.get_grade_clean($sum->sum).'</td>';
+ }
+ }
+ $groupsumhtml .= '</tr>';
+ }
+ return $groupsumhtml;
+ }
+
+ function get_gradesumhtml() {
+ global $CFG;
+
+ $gradesumhtml = '';
+ if ($this->showgrandtotals) {
+
+ /** SQL for finding the SUM grades of all visible users ($CFG->gradebookroles) */
+
+ $SQL = "SELECT g.itemid, SUM(g.finalgrade) as sum
+ FROM {$CFG->prefix}grade_items gi LEFT JOIN
+ {$CFG->prefix}grade_grades g ON gi.id = g.itemid RIGHT OUTER JOIN
+ {$CFG->prefix}user u ON u.id = g.userid LEFT JOIN
+ {$CFG->prefix}role_assignments ra ON u.id = ra.userid
+ WHERE gi.courseid = $this->courseid
+ AND ra.roleid in ($this->gradebookroles)
+ AND ra.contextid ".get_related_contexts_string($this->context)."
+ GROUP BY g.itemid";
+
+ $classsum = array();
+ $sums = get_records_sql($SQL);
+ foreach ($sums as $itemid => $csum) {
+ $classsum[$itemid] = $csum;
+ }
+
+ $gradesumhtml = '<tr><th>Total</th>';
+ foreach ($this->items as $item) {
+ if (!isset($classsum[$item->id])) {
+ $gradesumhtml .= '<td>-</td>';
+ } else {
+ $sum = $classsum[$item->id];
+ $gradesumhtml .= '<td>'.get_grade_clean($sum->sum).'</td>';
+ }
+ }
+ $gradesumhtml .= '</tr>';
+ }
+ return $gradesumhtml;
+ }
+
+ function get_scalehtml() {
+ $scalehtml = '';
+ if ($this->showscales) {
+ $scalehtml = '<tr><td>'.get_string('range','grades').'</td>';
+ foreach ($this->items as $item) {
+ $scalehtml .= '<td>'. get_grade_clean($item->grademin).'-'. get_grade_clean($item->grademax).'</td>';
+ }
+ $scalehtml .= '</tr>';
+ }
+ return $scalehtml;
+ }
+
+ /**
+ * Given a grade_category, grade_item or grade_grade, this function
+ * figures out the state of the object and builds then returns a div
+ * with the icons needed for the grader report.
+ *
+ * @param object $object
+ * @param array $icons An array of icon names that this function is explicitly requested to print, regardless of settings
+ * @param bool $limit If true, use the $icons array as the only icons that will be printed. If false, use it to exclude these icons.
+ * @return string HTML
+ */
+ function get_icons($element, $icons=null, $limit=true) {
+ global $CFG;
+ global $USER;
+
+ // Load language strings
+ $stredit = get_string("edit");
+ $streditcalculation= get_string("editcalculation", 'grades');
+ $strfeedback = get_string("feedback");
+ $strmove = get_string("move");
+ $strmoveup = get_string("moveup");
+ $strmovedown = get_string("movedown");
+ $strmovehere = get_string("movehere");
+ $strcancel = get_string("cancel");
+ $stredit = get_string("edit");
+ $strdelete = get_string("delete");
+ $strhide = get_string("hide");
+ $strshow = get_string("show");
+ $strlock = get_string("lock", 'grades');
+ $strswitch_minus = get_string("contract", 'grades');
+ $strswitch_plus = get_string("expand", 'grades');
+ $strunlock = get_string("unlock", 'grades');
+
+ // Prepare container div
+ $html = '<div class="grade_icons">';
+
+ // Prepare reference variables
+ $eid = $element['eid'];
+ $object = $element['object'];
+ $type = $element['type'];
+
+ // Add mock attributes in case the object is not of the right type
+ if ($type != 'grade') {
+ $object->feedback = '';
+ }
+
+ // Load user preferences
+ $aggregationview = get_user_preferences('grade_report_aggregationview', $CFG->grade_report_aggregationview);
+ $showeyecons = get_user_preferences('grade_report_showeyecons', $CFG->grade_report_showeyecons);
+ $showlocks = get_user_preferences('grade_report_showlocks', $CFG->grade_report_showlocks);
+ $showcalculations = get_user_preferences('grade_report_showcalculations', $CFG->grade_report_showcalculations);
+
+ // Prepare image strings
+ $edit_category_icon = '<a href="report/grader/edit_category.php?courseid='.$object->courseid.'&id='.$object->id.'">'
+ . '<img src="'.$CFG->pixpath.'/t/edit.gif" class="iconsmall" alt="'
+ . $stredit.'" title="'.$stredit.'" /></a>'. "\n";
+
+ $edit_item_icon = '<a href="report/grader/edit_item.php?courseid='.$object->courseid.'&id='.$object->id.'">'
+ . '<img src="'.$CFG->pixpath.'/t/edit.gif" class="iconsmall" alt="'
+ . $stredit.'" title="'.$stredit.'" /></a>'. "\n";
+ $overlib = '';
+ if (!empty($object->feedback)) {
+ $overlib = 'onmouseover="return overlib(\''.$object->feedback.'\', CAPTION, \''
+ . $strfeedback.'\');" onmouseout="return nd();"';
+ }
+
+ $edit_grade_icon = '<a href="report/grader/edit_grade.php?courseid='.$object->courseid.'&id='.$object->id.'">'
+ . '<img ' . $overlib . ' src="'.$CFG->pixpath.'/t/edit.gif"'
+ . 'class="iconsmall" alt="' . $stredit.'" title="'.$stredit.'" /></a>'. "\n";
+
+
+ $edit_calculation_icon = '<a href="report/grader/edit_calculation.php?courseid='.$object->courseid.'&id='.$object->id.'">'
+ . '<img src="'.$CFG->pixpath.'/t/calc.gif" class="iconsmall" alt="'
+ . $streditcalculation.'" title="'.$streditcalculation.'" /></a>'. "\n";
+
+ // Prepare Hide/Show icon state
+ $hide_show = 'hide';
+ if ($object->is_hidden()) {
+ $hide_show = 'show';
+ }
+
+ $show_hide_icon = '<a href="report.php?report=grader&target='.$eid
+ . "&action=$hide_show" . $this->gtree->commonvars . "\">\n"
+ . '<img src="'.$CFG->pixpath.'/t/'.$hide_show.'.gif" class="iconsmall" alt="'
+ . ${'str' . $hide_show}.'" title="'.${'str' . $hide_show}.'" /></a>'. "\n";
+
+ // Prepare lock/unlock string
+ $lock_unlock = 'lock';
+ if ($object->is_locked()) {
+ $lock_unlock = 'unlock';
+ }
+
+ // Print lock/unlock icon
+
+ $lock_unlock_icon = '<a href="report.php?report=grader&target='.$eid
+ . "&action=$lock_unlock" . $this->gtree->commonvars . "\">\n"
+ . '<img src="'.$CFG->pixpath.'/t/'.$lock_unlock.'.gif" class="iconsmall" alt="'
+ . ${'str' . $lock_unlock}.'" title="'.${'str' . $lock_unlock}.'" /></a>'. "\n";
+
+ // Prepare expand/contract string
+ $expand_contract = 'switch_minus'; // Default: expanded
+ $state = get_user_preferences('grade_category_' . $object->id, GRADE_CATEGORY_EXPANDED);
+ if ($state == GRADE_CATEGORY_CONTRACTED) {
+ $expand_contract = 'switch_plus';
+ }
+
+ $contract_expand_icon = '<a href="report.php?report=grader&target=' . $eid
+ . "&action=$expand_contract" . $this->gtree->commonvars . "\">\n"
+ . '<img src="'.$CFG->pixpath.'/t/'.$expand_contract.'.gif" class="iconsmall" alt="'
+ . ${'str' . $expand_contract}.'" title="'.${'str' . $expand_contract}.'" /></a>'. "\n";
+
+ // If an array of icon names is given, return only these in the order they are given
+ if (!empty($icons) && is_array($icons)) {
+ $new_html = '';
+
+ foreach ($icons as $icon_name) {
+ if ($icon_name == 'edit') {
+ $icon_name .= "_$type";
+ }
+ if ($limit) {
+ $new_html .= ${$icon_name . '_icon'};
+ } else {
+ ${'show_' . $icon_name} = false;
+ }
+ }
+ if ($limit) {
+ return $new_html;
+ } else {
+ $html .= $new_html;
+ }
+ }
+
+ // Icons shown when edit mode is on
+ if ($USER->gradeediting) {
+ // Edit icon (except for grade_grades)
+ if ($type == 'category') {
+ $html .= $edit_category_icon;
+
+ } else if ($type == 'item' or $type == 'courseitem' or $type == 'categoryitem') {
+ $html .= $edit_item_icon;
+ }
+
+ // Calculation icon for items and categories
+ if ($showcalculations && $type != 'grade') {
+ $html .= $edit_calculation_icon;
+ }
+
+ if ($showeyecons) {
+ $html .= $show_hide_icon;
+ }
+
+ if ($showlocks) {
+ $html .= $lock_unlock_icon;
+ }
+
+ // If object is a category, display expand/contract icon
+ if (get_class($object) == 'grade_category' && $aggregationview == GRADER_REPORT_AGGREGATION_VIEW_COMPACT) {
+ $html .= $contract_expand_icon;
+ }
+ } else { // Editing mode is off
+ }
+
+ return $html . '</div>';
+ }
+}
+?>
/// This creates and handles the whole grader report interface, sans header and footer
-require_once($CFG->libdir.'/tablelib.php');
-require_once($CFG->libdir.'/gradelib.php');
-require_once($CFG->dirroot.'/grade/report/lib.php');
+require_once($CFG->dirroot.'/grade/report/grader/grader_report.php');
$gradeserror = array();
-/**
-* Shortcut function for printing the grader report toggles.
-* @param string $type The type of toggle
-* @param string $baseurl The base of the URL the toggles will link to
-* @param bool $return Whether to return the HTML string rather than printing it
-* @return void
-*/
-function grader_report_print_toggle($type, $baseurl, $return=false) {
- global $CFG;
-
- $icons = array('eyecons' => 'hide',
- 'calculations' => 'calc',
- 'locks' => 'lock',
- 'grandtotals' => 'sigma');
-
- $pref_name = 'grade_report_show' . $type;
- $show_pref = get_user_preferences($pref_name, $CFG->$pref_name);
-
- $strshow = get_string('show' . $type, 'grades');
- $strhide = get_string('hide' . $type, 'grades');
-
- $show_hide = 'show';
- $toggle_action = 1;
-
- if ($show_pref) {
- $show_hide = 'hide';
- $toggle_action = 0;
- }
-
- if (array_key_exists($type, $icons)) {
- $image_name = $icons[$type];
- } else {
- $image_name = $type;
- }
-
- $string = ${'str' . $show_hide};
-
- $img = '<img src="'.$CFG->pixpath.'/t/'.$image_name.'.gif" class="iconsmall" alt="'
- .$string.'" title="'.$string.'" />'. "\n";
-
- $retval = '<div class="gradertoggle">' . $img . '<a href="' . $baseurl . "&toggle=$toggle_action&toggle_type=$type\">"
- . $string . '</a></div>';
-
- if ($return) {
- return $retval;
- } else {
- echo $retval;
- }
-}
-
-
-/// processing posted grades & feedback here
-
-if ($data = data_submitted() and confirm_sesskey()) {
-
- // always initialize all arrays
- $queue = array();
-
- foreach ($data as $varname => $postedvalue) {
- // this is a bit tricky - we have to first load all grades into memory,
- // check if changed and only then start updating the final grades because
- // columns might depend one on another - the result would be overriden calculated and category grades
-
- $needsupdate = false;
- $note = false; // TODO implement note??
-
- // skip, not a grade nor feedback
- $data_type = '';
- if (strstr($varname, 'grade')) {
- $data_type = 'grade';
- } elseif (strstr($varname, 'feedback')) {
- $data_type = 'feedback';
- } else {
- continue;
- }
-
- $gradeinfo = explode("_", $varname);
-
- $userid = clean_param($gradeinfo[1], PARAM_INT);
- $itemid = clean_param($gradeinfo[2], PARAM_INT);
-
- if (!$grade_item = grade_item::fetch(array('id'=>$itemid, 'courseid'=>$course->id))) { // we must verify course id here!
- error('Incorrect grade item id');
- }
-
- // Pre-process grade
- if ($data_type == 'grade') {
-
- if ($grade_item->gradetype == GRADE_TYPE_SCALE) {
- if ($postedvalue == -1) { // -1 means no grade
- $finalgrade = null;
- } else {
- $finalgrade = (float)$postedvalue;
- }
- } else {
- if ($postedvalue == '') { // empty string means no grade
- $finalgrade = null;
- } else {
- $finalgrade = format_grade($postedvalue);
- }
- }
-
- if (!is_null($finalgrade) and ($finalgrade < $grade_item->grademin or $finalgrade > $grade_item->grademax)) {
- $gradeserror[$grade_item->id][$userid] = 'outofrange'; //TODO: localize
- // another possiblity is to use bounded number instead
- continue;
- }
- }
-
- // Get the grade object to compare old value with new value
- if ($grade = grade_grades::fetch(array('userid'=>$userid, 'itemid'=>$grade_item->id))) {
- if ($data_type == 'feedback') {
- $finalgrade = false;
- $text = $grade->load_text();
- if ($text != s($postedvalue)) {
- $feedback = s($postedvalue);
- $feedbackformat = GRADER_REPORT_FEEDBACK_FORMAT_TEXT;
- $needsupdate = true;
- }
- } elseif ($data_type == 'grade') {
- $feedback = false;
- $feedbackformat = false;
- if (!is_null($grade->finalgrade)) {
- $grade->finalgrade = (float)$grade->finalgrade;
- }
- if ($grade->finalgrade === $finalgrade) {
- $needsupdate = true;
- }
- }
-
- }
-
- // we must not update all grades, only changed ones - we do not want to mark everything as overriden
- if ($needsupdate) {
- $gradedata = new object();
- $gradedata->grade_item = $grade_item;
- $gradedata->userid = $userid;
- $gradedata->note = $note;
- $gradedata->finalgrade = $finalgrade;
- $gradedata->feedback = $feedback;
- $gradedata->feedbackformat = $feedbackformat;
-
- $queue[] = $gradedata;
- }
- }
-
- // now we update the new final grade for each changed grade
- foreach ($queue as $gradedata) {
- $gradedata->grade_item->update_final_grade($gradedata->userid, $gradedata->finalgrade, 'gradebook',
- $gradedata->note, $gradedata->feedback, $gradedata->feedbackformat);
- }
-}
-
-// get the params
-$courseid = required_param('id', PARAM_INT);
-$context = get_context_instance(CONTEXT_COURSE, $courseid);
+// get the params ($report, $courseid and $context are already set in grade/report.php)
$page = optional_param('page', 0, PARAM_INT);
$sortitemid = optional_param('sortitemid', 0, PARAM_ALPHANUM); // sort by which grade item
-$report = optional_param('report', 0, PARAM_ALPHANUM);
$action = optional_param('action', 0, PARAM_ALPHA);
$move = optional_param('move', 0, PARAM_INT);
$type = optional_param('type', 0, PARAM_ALPHA);
$target = optional_param('target', 0, PARAM_ALPHANUM);
$toggle = optional_param('toggle', NULL, PARAM_INT);
$toggle_type = optional_param('toggle_type', 0, PARAM_ALPHANUM);
-
+$db->debug=true;
// Handle toggle change request
-// TODO print visual feedback
if (!is_null($toggle) && !empty($toggle_type)) {
set_user_preferences(array('grade_report_show' . $toggle_type => $toggle));
}
-// Get the user preferences
-$perpage = get_user_preferences('grade_report_studentsperpage', $CFG->grade_report_studentsperpage); // number of users on a page
-$decimals = get_user_preferences('grade_report_decimalpoints', $CFG->grade_report_decimalpoints); // decimals in grades
-$showgrandtotals = get_user_preferences('grade_report_showgrandtotals', $CFG->grade_report_showgrandtotals);
-$showgroups = get_user_preferences('grade_report_showgroups', $CFG->grade_report_showgroups);
-$aggregation_position = get_user_preferences('grade_report_aggregationposition', $CFG->grade_report_aggregationposition);
-$showscales = get_user_preferences('grade_report_showscales', $CFG->grade_report_showscales);
-$quickgrading = get_user_preferences('grade_report_quickgrading', $CFG->grade_report_quickgrading);
-$quickfeedback = get_user_preferences('grade_report_quickfeedback', $CFG->grade_report_quickfeedback);
+// Initialise the grader report object
+$report = new grade_report_grader($courseid, $context, $page, $sortitemid);
-// Override perpage if set in URL
-if ($perpageurl = optional_param('perpage', 0, PARAM_INT)) {
- $perpage = $perpageurl;
-}
-
-// Prepare language strings
-$strsortasc = get_string('sortasc', 'grades');
-$strsortdesc = get_string('sortdesc', 'grades');
-$strfeedback = get_string("feedback");
-
-// base url for sorting by first/last name
-$baseurl = 'report.php?id='.$courseid.'&perpage='.$perpage.'&report=grader&page='.$page;
-// base url for paging
-$pbarurl = 'report.php?id='.$courseid.'&perpage='.$perpage.'&report=grader&';
-
-/// setting up groups
-$groupsql = '';
-$groupwheresql = '';
-$group_selector = null;
-$currentgroup = null;
-
-if ($showgroups) {
- /// find out current groups mode
- $course = get_record('course', 'id', $courseid);
- $groupmode = $course->groupmode;
- ob_start();
- $currentgroup = setup_and_print_groups($course, $groupmode, $baseurl);
- $group_selector = ob_get_clean();
-
- // update paging after group
- $baseurl .= 'group='.$currentgroup.'&';
- $pbarurl .= 'group='.$currentgroup.'&';
-
- if ($currentgroup) {
- $groupsql = " LEFT JOIN {$CFG->prefix}groups_members gm ON gm.userid = u.id ";
- $groupwheresql = " AND gm.groupid = $currentgroup ";
- }
+/// processing posted grades & feedback here
+if ($data = data_submitted() and confirm_sesskey()) {
+ $report->process_data($data);
}
-// Grab the grade_tree for this course
-$gtree = new grade_tree($courseid, true, false, $aggregation_position);
-
-// 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
-
-// already in not requesting sort, i.e. normal paging
-
-if ($sortitemid) {
- if (!isset($SESSION->gradeuserreport->sort)) {
- $sortorder = $SESSION->gradeuserreport->sort = 'ASC';
- } else {
- // this is the first sort, i.e. by last name
- if (!isset($SESSION->gradeuserreport->sortitemid)) {
- $sortorder = $SESSION->gradeuserreport->sort = 'ASC';
- } else if ($SESSION->gradeuserreport->sortitemid == $sortitemid) {
- // same as last sort
- if ($SESSION->gradeuserreport->sort == 'ASC') {
- $sortorder = $SESSION->gradeuserreport->sort = 'DESC';
- } else {
- $sortorder = $SESSION->gradeuserreport->sort = 'ASC';
- }
- } else {
- $sortorder = $SESSION->gradeuserreport->sort = 'ASC';
- }
- }
- $SESSION->gradeuserreport->sortitemid = $sortitemid;
-} else {
- // not requesting sort, use last setting (for paging)
-
- if (isset($SESSION->gradeuserreport->sortitemid)) {
- $sortitemid = $SESSION->gradeuserreport->sortitemid;
- }
- if (isset($SESSION->gradeuserreport->sort)) {
- $sortorder = $SESSION->gradeuserreport->sort;
- } else {
- $sortorder = 'ASC';
- }
+// Override perpage if set in URL
+if ($perpageurl = optional_param('perpage', 0, PARAM_INT)) {
+ $report->studentsperpage = $perpageurl;
}
-/// end of setting sort order code
-
// Perform actions on categories, items and grades
if (!empty($target) && !empty($action) && confirm_sesskey()) {
-
- $element = $gtree->locate_element($target);
-
- switch ($action) {
- case 'edit':
- break;
- case 'delete':
- if ($confirm == 1) { // Perform the deletion
- //TODO: add proper delete support for grade items and categories
- //$element['object']->delete();
- // Print result message
-
- } else { // Print confirmation dialog
- $eid = $element['eid'];
- $strdeletecheckfull = get_string('deletecheck', '', $element['object']->get_name());
- $linkyes = "category.php?target=$eid&action=delete&confirm=1$gtree->commonvars";
- $linkno = "category.php?$gtree->commonvars";
- notice_yesno($strdeletecheckfull, $linkyes, $linkno);
- }
- break;
-
- case 'hide':
- // TODO Implement calendar for selection of a date to hide element until
- $element['object']->set_hidden(1);
- $gtree = new grade_tree($courseid);
- break;
- case 'show':
- $element['object']->set_hidden(0);
- $gtree = new grade_tree($courseid);
- break;
- case 'lock':
- // TODO Implement calendar for selection of a date to lock element after
- if (!$element['object']->set_locked(1)) {
- debugging("Could not update the element's locked state!");
- }
- $gtree = new grade_tree($courseid);
- break;
- case 'unlock':
- if (!$element['object']->set_locked(0)) {
- debugging("Could not update the element's locked state!");
- }
- $gtree = new grade_tree($courseid);
- break;
- default:
- break;
- }
+ $report->process_action($target, $action);
}
// first make sure we have all final grades
// TODO: check that no grade_item has needsupdate set
grade_regrade_final_grades($courseid);
-// roles to be displaye in the gradebook
-$gradebookroles = $CFG->gradebookroles;
-
-/*
-* pulls out the userids of the users to be display, and sort them
-* the right outer join is needed because potentially, it is possible not
-* to have the corresponding entry in grade_grades table for some users
-* this is check for user roles because there could be some users with grades
-* but not supposed to be displayed
-*/
-if (is_numeric($sortitemid)) {
- $sql = "SELECT u.id, u.firstname, u.lastname
- FROM {$CFG->prefix}grade_grades g RIGHT OUTER JOIN
- {$CFG->prefix}user u ON (u.id = g.userid AND g.itemid = $sortitemid)
- LEFT JOIN {$CFG->prefix}role_assignments ra ON u.id = ra.userid
- $groupsql
- WHERE ra.roleid in ($gradebookroles)
- $groupwheresql
- AND ra.contextid ".get_related_contexts_string($context)."
- ORDER BY g.finalgrade $sortorder";
- $users = get_records_sql($sql, $perpage * $page, $perpage);
-} else {
- // default sort
- // get users sorted by lastname
- $users = get_role_users(@implode(',', $CFG->gradebookroles), $context, false, 'u.id, u.firstname, u.lastname', 'u.'.$sortitemid .' '. $sortorder, false, $page * $perpage, $perpage, $currentgroup);
- // need to cut users down by groups
-
-}
-
-/// count total records for paging
-
-$countsql = "SELECT COUNT(DISTINCT u.id)
- FROM {$CFG->prefix}grade_grades g RIGHT OUTER JOIN
- {$CFG->prefix}user u ON (u.id = g.userid AND g.itemid = $sortitemid)
- LEFT JOIN {$CFG->prefix}role_assignments ra ON u.id = ra.userid
- $groupsql
- WHERE ra.roleid in ($gradebookroles)
- $groupwheresql
- AND ra.contextid ".get_related_contexts_string($context);
-$numusers = count_records_sql($countsql);
-
-// print_object($users); // debug
-
-if (empty($users)) {
- $userselect = '';
- $users = array();
-} else {
- $userselect = 'AND g.userid in ('.implode(',', array_keys($users)).')';
-}
-
-
-// phase 2 sql, we supply the userids in this query, and get all the grades
-// pulls out all the grades, this does not need to worry about paging
-$sql = "SELECT g.id, g.itemid, g.userid, g.finalgrade, g.hidden, g.locked, g.locktime, g.overridden, gt.feedback
- FROM {$CFG->prefix}grade_items gi,
- {$CFG->prefix}grade_grades g
- LEFT JOIN {$CFG->prefix}grade_grades_text gt ON g.id = gt.gradeid
- WHERE g.itemid = gi.id
- AND gi.courseid = $courseid $userselect";
-
-///print_object($grades); //debug
-
-$finalgrades = array();
-// needs to be formatted into an array for easy retrival
-
-if ($grades = get_records_sql($sql)) {
- foreach ($grades as $grade) {
- $finalgrades[$grade->userid][$grade->itemid] = $grade;
- }
-}
-
-/// With the users in an sorted array and grades fetched, we can not print the main html table
+$report->load_users();
+$numusers = $report->get_numusers();
+$report->load_final_grades();
-// 1. Fetch all top-level categories for this course, with all children preloaded, sorted by sortorder
-
- // Fetch array of students enroled in this course
-if (!$context = get_context_instance(CONTEXT_COURSE, $gtree->courseid)) {
+if (!$context = get_context_instance(CONTEXT_COURSE, $report->gtree->courseid)) {
return false;
}
-//$users = get_role_users(@implode(',', $CFG->gradebookroles), $context);
-
-if ($sortitemid === 'lastname') {
- if ($sortorder == 'ASC') {
- $lastarrow = print_arrow('up', $strsortasc, true);
- } else {
- $lastarrow = print_arrow('down', $strsortdesc, true);
- }
-} else {
- $lastarrow = '';
-}
-
-if ($sortitemid === 'firstname') {
- if ($sortorder == 'ASC') {
- $firstarrow = print_arrow('up', $strsortasc, true);
- } else {
- $firstarrow = print_arrow('down', $strsortdesc, true);
- }
-} else {
- $firstarrow = '';
-}
-
-/********* BEGIN OUTPUT *********/
print_heading('Grader Report');
$currenttab = 'graderreport';
include('tabs.php');
-// Group selection drop-down
-echo $group_selector;
-
-// Show/hide toggles
-echo '<div id="grade-report-toggles">';
-if ($USER->gradeediting) {
- grader_report_print_toggle('eyecons', $baseurl);
- grader_report_print_toggle('locks', $baseurl);
- grader_report_print_toggle('calculations', $baseurl);
-}
-
-grader_report_print_toggle('grandtotals', $baseurl);
-grader_report_print_toggle('groups', $baseurl);
-grader_report_print_toggle('scales', $baseurl);
-echo '</div>';
-
-// Paging bar
-print_paging_bar($numusers, $page, $perpage, $pbarurl);
-
-$items = array();
-
-// Prepare Table Headers
-$headerhtml = '';
-
-$numrows = count($gtree->levels);
-
-foreach ($gtree->levels as $key=>$row) {
- if ($key == 0) {
- // do not diplay course grade category
- // continue;
- }
-
- $headerhtml .= '<tr class="heading">';
-
- if ($key == $numrows - 1) {
- $headerhtml .= '<th class="user"><a href="'.$baseurl.'&sortitemid=firstname">Firstname</a> ' //TODO: localize
- . $firstarrow. '/ <a href="'.$baseurl.'&sortitemid=lastname">Lastname </a>'. $lastarrow .'</th>';
- } else {
- $headerhtml .= '<td class="topleft"> </td>';
- }
-
- foreach ($row as $element) {
- $eid = $element['eid'];
- $object = $element['object'];
- $type = $element['type'];
-
- if (!empty($element['colspan'])) {
- $colspan = 'colspan="'.$element['colspan'].'"';
- } else {
- $colspan = '';
- }
-
- if (!empty($element['depth'])) {
- $catlevel = ' catlevel'.$element['depth'];
- } else {
- $catlevel = '';
- }
-
-
- if ($type == 'filler' or $type == 'fillerfirst' or $type == 'fillerlast') {
- $headerhtml .= '<td class="'.$type.$catlevel.'" '.$colspan.'> </td>';
- } else if ($type == 'category') {
- $headerhtml .= '<td class="category'.$catlevel.'" '.$colspan.'>'.$element['object']->get_name();
-
- // Print icons
- if ($USER->gradeediting) {
- $headerhtml .= grade_get_icons($element, $gtree);
- }
-
- $headerhtml .= '</td>';
- } else {
- if ($element['object']->id == $sortitemid) {
- if ($sortorder == 'ASC') {
- $arrow = print_arrow('up', $strsortasc, true);
- } else {
- $arrow = print_arrow('down', $strsortdesc, true);
- }
- } else {
- $arrow = '';
- }
-
- $dimmed = '';
- if ($element['object']->is_hidden()) {
- $dimmed = ' dimmed_text ';
- }
-
- if ($object->itemtype == 'mod') {
- $icon = '<img src="'.$CFG->modpixpath.'/'.$object->itemmodule.'/icon.gif" class="icon" alt="'
- .get_string('modulename', $object->itemmodule).'"/>';
- } else if ($object->itemtype == 'manual') {
- //TODO: add manual grading icon
- $icon = '<img src="'.$CFG->pixpath.'/t/edit.gif" class="icon" alt="'.get_string('manualgrade', 'grades')
- .'"/>';
- }
-
-
- $headerhtml .= '<th class="'.$type.$catlevel.$dimmed.'"><a href="'.$baseurl.'&sortitemid='
- . $element['object']->id .'">'. $element['object']->get_name()
- . '</a>' . $arrow;
-
- $headerhtml .= grade_get_icons($element, $gtree) . '</th>';
-
- $items[$element['object']->sortorder] =& $element['object'];
- }
-
- }
-
- $headerhtml .= '</tr>';
-}
-
-// Prepare Table Rows
-$studentshtml = '';
-
-foreach ($users as $userid => $user) {
- // Student name and link
- $studentshtml .= '<tr><th class="user"><a href="' . $CFG->wwwroot . '/user/view.php?id='
- . $user->id . '">' . fullname($user) . '</a></th>';
- foreach ($items as $item) {
-
- if (isset($finalgrades[$userid][$item->id])) {
- $gradeval = $finalgrades[$userid][$item->id]->finalgrade;
- $grade = new grade_grades($finalgrades[$userid][$item->id], false);
- $grade->feedback = $finalgrades[$userid][$item->id]->feedback;
-
- } else {
- $gradeval = null;
- $grade = new grade_grades(array('userid' => $userid, 'itemid' => $item->id), false);
- $grade->feedback = '';
- }
-
- if ($grade->is_overridden()) {
- $studentshtml .= '<td class="overridden">';
- } else {
- $studentshtml .= '<td>';
- }
-
- // Do not show any icons if no grade (no record in DB to match)
- if (!empty($grade->id)) {
- // emulate grade element
- $grade->courseid = $course->id;
- $grade->grade_item = $item; // this may speedup is_hidden() and other grade_grades methods
- $element = array ('eid'=>'g'.$grade->id, 'object'=>$grade, 'type'=>'grade');
- $studentshtml .= grade_get_icons($element, $gtree);
- }
-
-
- // if in editting 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
- if ($USER->gradeediting) {
- // We need to retrieve each grade_grade object from DB in order to
- // know if they are hidden/locked
-
- if ($item->scaleid) {
- if ($scale = get_record('scale', 'id', $item->scaleid)) {
- $scales = explode(",", $scale->scale);
- // reindex because scale is off 1
- $i = 0;
- foreach ($scales as $scaleoption) {
- $i++;
- $scaleopt[$i] = $scaleoption;
- }
-
- if ($quickgrading) {
- $studentshtml .= choose_from_menu($scaleopt, 'grade_'.$userid.'_'.$item->id,
- $gradeval, get_string('nograde'), '', -1, true);
- } elseif ($scale = get_record('scale', 'id', $item->scaleid)) {
- $scales = explode(",", $scale->scale);
-
- // invalid grade if gradeval < 1
- if ((int) $gradeval < 1) {
- $studentshtml .= '-';
- } else {
- $studentshtml .= $scales[$gradeval-1];
- }
- } else {
- // no such scale, throw error?
- }
- }
- } else {
- if ($quickgrading) {
- $studentshtml .= '<input size="6" type="text" name="grade_'.$userid.'_'.$item->id.'" value="'.get_grade_clean($gradeval).'"/>';
- } else {
- $studentshtml .= get_grade_clean($gradeval);
- }
- }
-
-
- // If quickfeedback is on, print an input element
- if ($quickfeedback) {
- $studentshtml .= '<input size="6" type="text" name="feedback_'.$userid.'_'.$item->id.'" value="'. s($grade->feedback) . '"/>';
- }
-
- $studentshtml .= '<div class="grade_icons">' . grade_get_icons($element, $gtree, array('edit')) . '</div>';
- } else {
- // If feedback present, surround grade with feedback tooltip
- if (!empty($grade->feedback)) {
- $studentshtml .= '<span onmouseover="return overlib(\''.$grade->feedback.'\', CAPTION, \''
- . $strfeedback.'\');" onmouseout="return nd();">';
- }
-
- // finalgrades[$userid][$itemid] could be null because of the outer join
- // in this case it's different than a 0
- if ($item->scaleid) {
- if ($scale = get_record('scale', 'id', $item->scaleid)) {
- $scales = explode(",", $scale->scale);
-
- // invalid grade if gradeval < 1
- if ((int) $gradeval < 1) {
- $studentshtml .= '-';
- } else {
- $studentshtml .= $scales[$gradeval-1];
- }
- } else {
- // no such scale, throw error?
- }
- } else {
- if (is_null($gradeval)) {
- $studentshtml .= '-';
- } else {
- $studentshtml .= get_grade_clean($gradeval);
- }
- }
- if (!empty($grade->feedback)) {
- $studentshtml .= '</span>';
- }
- }
-
- if (!empty($gradeserror[$item->id][$userid])) {
- $studentshtml .= $gradeserror[$item->id][$userid];
- }
-
- $studentshtml .= '</td>' . "\n";
- }
- $studentshtml .= '</tr>';
-}
-
-// if user preference to display group sum
-$groupsumhtml = '';
-
-if ($currentgroup && $showgroups) {
-
-/** SQL for finding group sum */
- $SQL = "SELECT g.itemid, SUM(g.finalgrade) as sum
- FROM {$CFG->prefix}grade_items gi LEFT JOIN
- {$CFG->prefix}grade_grades g ON gi.id = g.itemid RIGHT OUTER JOIN
- {$CFG->prefix}user u ON u.id = g.userid LEFT JOIN
- {$CFG->prefix}role_assignments ra ON u.id = ra.userid
- $groupsql
- WHERE gi.courseid = $courseid
- $groupwheresql
- AND ra.roleid in ($gradebookroles)
- AND ra.contextid ".get_related_contexts_string($context)."
- GROUP BY g.itemid";
-
- $groupsum = array();
- $sums = get_records_sql($SQL);
- foreach ($sums as $itemid => $csum) {
- $groupsum[$itemid] = $csum;
- }
-
- $groupsumhtml = '<tr><th>Group total</th>';
- foreach ($items as $item) {
- if (!isset($groupsum[$item->id])) {
- $groupsumhtml .= '<td>-</td>';
- } else {
- $sum = $groupsum[$item->id];
- $groupsumhtml .= '<td>'.get_grade_clean($sum->sum).'</td>';
- }
- }
- $groupsumhtml .= '</tr>';
-}
-
-// Grand totals
-$gradesumhtml = '';
-if ($showgrandtotals) {
-
-/** SQL for finding the SUM grades of all visible users ($CFG->gradebookroles) */
-
- $SQL = "SELECT g.itemid, SUM(g.finalgrade) as sum
- FROM {$CFG->prefix}grade_items gi LEFT JOIN
- {$CFG->prefix}grade_grades g ON gi.id = g.itemid RIGHT OUTER JOIN
- {$CFG->prefix}user u ON u.id = g.userid LEFT JOIN
- {$CFG->prefix}role_assignments ra ON u.id = ra.userid
- WHERE gi.courseid = $courseid
- AND ra.roleid in ($gradebookroles)
- AND ra.contextid ".get_related_contexts_string($context)."
- GROUP BY g.itemid";
-
- $classsum = array();
- $sums = get_records_sql($SQL);
- foreach ($sums as $itemid => $csum) {
- $classsum[$itemid] = $csum;
- }
-
- $gradesumhtml = '<tr><th>Total</th>';
- foreach ($items as $item) {
- if (!isset($classsum[$item->id])) {
- $gradesumhtml .= '<td>-</td>';
- } else {
- $sum = $classsum[$item->id];
- $gradesumhtml .= '<td>'.get_grade_clean($sum->sum).'</td>';
- }
- }
- $gradesumhtml .= '</tr>';
-}
-
-// finding the ranges of each gradeitem
-$scalehtml = '';
-if ($showscales) {
- $scalehtml = '<tr><td>'.get_string('range','grades').'</td>';
- foreach ($items as $item) {
- $scalehtml .= '<td>'. get_grade_clean($item->grademin).'-'. get_grade_clean($item->grademax).'</td>';
- }
- $scalehtml .= '</tr>';
-}
-
-echo "<br/>";
-
-$reporthtml = "<table class=\"boxaligncenter\">$headerhtml";
-$reporthtml .= $scalehtml;
-$reporthtml .= $studentshtml;
-$reporthtml .= $groupsumhtml;
-$reporthtml .= $gradesumhtml;
+echo $report->group_selector;
+echo $report->get_toggles_html();
+print_paging_bar($numusers, $report->page, $report->studentsperpage, $report->pbarurl);
+echo '<br />';
+
+$reporthtml = '<table class="boxaligncenter">';
+$reporthtml .= $report->get_headerhtml();
+$reporthtml .= $report->get_scalehtml();
+$reporthtml .= $report->get_studentshtml();
+$reporthtml .= $report->get_groupsumhtml();
+$reporthtml .= $report->get_gradesumhtml();
$reporthtml .= "</table>";
-
// print submit button
if ($USER->gradeediting) {
echo '<form action="report.php" method="post">';
echo $reporthtml;
// print submit button
-if ($USER->gradeediting && ($quickfeedback || $quickgrading)) {
+if ($USER->gradeediting && ($report->quickfeedback || $report->quickgrading)) {
echo '<div class="submit"><input type="submit" value="'.get_string('update').'" /></div>';
echo '</div></form>';
}
// prints paging bar at bottom for large pages
-if ($perpage >= 20) {
- print_paging_bar($numusers, $page, $perpage, $pbarurl);
+if ($report->studentsperpage >= 20) {
+ print_paging_bar($numusers, $report->page, $report->studentsperpage, $report->pbarurl);
}
?>
define('GRADE_HISTORY_UPDATE', 2);
define('GRADE_HISTORY_DELETE', 3);
-// Set up constants for report preferences
-define('GRADER_REPORT_AGGREGATION_POSITION_LEFT', 0);
-define('GRADER_REPORT_AGGREGATION_POSITION_RIGHT', 1);
-define('GRADER_REPORT_AGGREGATION_VIEW_FULL', 0);
-define('GRADER_REPORT_AGGREGATION_VIEW_COMPACT', 1);
-define('GRADER_REPORT_GRADE_DISPLAY_TYPE_RAW', 0);
-define('GRADER_REPORT_GRADE_DISPLAY_TYPE_PERCENTAGE', 1);
-define('GRADER_REPORT_FEEDBACK_FORMAT_TEXT', 0);
-define('GRADER_REPORT_FEEDBACK_FORMAT_HTML', 1);
-
require_once($CFG->libdir . '/grade/grade_category.php');
require_once($CFG->libdir . '/grade/grade_item.php');
}
}
-/**
- * Given a grade_category, grade_item or grade_grade, this function
- * figures out the state of the object and builds then returns a div
- * with the icons needed for the grader report.
- *
- * @param object $object
- * @param object $tree (A complete grade_tree object)
- * @param array $icons An array of icon names that this function is explicitly requested to print, regardless of settings
- * @param bool $limit If true, use the $icons array as the only icons that will be printed. If false, use it to exclude these icons.
- * @return string HTML
- */
-function grade_get_icons($element, $tree, $icons=null, $limit=true) {
- global $CFG;
- global $USER;
-
-
- // Load language strings
- $stredit = get_string("edit");
- $streditcalculation= get_string("editcalculation", 'grades');
- $strfeedback = get_string("feedback");
- $strmove = get_string("move");
- $strmoveup = get_string("moveup");
- $strmovedown = get_string("movedown");
- $strmovehere = get_string("movehere");
- $strcancel = get_string("cancel");
- $stredit = get_string("edit");
- $strdelete = get_string("delete");
- $strhide = get_string("hide");
- $strshow = get_string("show");
- $strlock = get_string("lock", 'grades');
- $strswitch_minus = get_string("contract", 'grades');
- $strswitch_plus = get_string("expand", 'grades');
- $strunlock = get_string("unlock", 'grades');
-
- // Prepare container div
- $html = '<div class="grade_icons">';
-
- // Prepare reference variables
- $eid = $element['eid'];
- $object = $element['object'];
- $type = $element['type'];
-
- // Add mock attributes in case the object is not of the right type
- if ($type != 'grade') {
- $object->feedback = '';
- }
-
- // Load user preferences
- $aggregationview = get_user_preferences('grade_report_aggregationview', $CFG->grade_report_aggregationview);
- $showeyecons = get_user_preferences('grade_report_showeyecons', $CFG->grade_report_showeyecons);
- $showlocks = get_user_preferences('grade_report_showlocks', $CFG->grade_report_showlocks);
- $showcalculations = get_user_preferences('grade_report_showcalculations', $CFG->grade_report_showcalculations);
-
- // Prepare image strings
- $edit_category_icon = '<a href="report/grader/edit_category.php?courseid='.$object->courseid.'&id='.$object->id.'">'
- . '<img src="'.$CFG->pixpath.'/t/edit.gif" class="iconsmall" alt="'
- . $stredit.'" title="'.$stredit.'" /></a>'. "\n";
-
- $edit_item_icon = '<a href="report/grader/edit_item.php?courseid='.$object->courseid.'&id='.$object->id.'">'
- . '<img src="'.$CFG->pixpath.'/t/edit.gif" class="iconsmall" alt="'
- . $stredit.'" title="'.$stredit.'" /></a>'. "\n";
- $overlib = '';
- if (!empty($object->feedback)) {
- $overlib = 'onmouseover="return overlib(\''.$object->feedback.'\', CAPTION, \''
- . $strfeedback.'\');" onmouseout="return nd();"';
- }
-
- $edit_grade_icon = '<a href="report/grader/edit_grade.php?courseid='.$object->courseid.'&id='.$object->id.'">'
- . '<img ' . $overlib . ' src="'.$CFG->pixpath.'/t/edit.gif"'
- . 'class="iconsmall" alt="' . $stredit.'" title="'.$stredit.'" /></a>'. "\n";
-
-
- $edit_calculation_icon = '<a href="report/grader/edit_calculation.php?courseid='.$object->courseid.'&id='.$object->id.'">'
- . '<img src="'.$CFG->pixpath.'/t/calc.gif" class="iconsmall" alt="'
- . $streditcalculation.'" title="'.$streditcalculation.'" /></a>'. "\n";
-
- // Prepare Hide/Show icon state
- $hide_show = 'hide';
- if ($object->is_hidden()) {
- $hide_show = 'show';
- }
-
- $show_hide_icon = '<a href="report.php?report=grader&target='.$eid
- . "&action=$hide_show$tree->commonvars\">\n"
- . '<img src="'.$CFG->pixpath.'/t/'.$hide_show.'.gif" class="iconsmall" alt="'
- . ${'str' . $hide_show}.'" title="'.${'str' . $hide_show}.'" /></a>'. "\n";
-
- // Prepare lock/unlock string
- $lock_unlock = 'lock';
- if ($object->is_locked()) {
- $lock_unlock = 'unlock';
- }
-
- // Print lock/unlock icon
-
- $lock_unlock_icon = '<a href="report.php?report=grader&target='.$eid
- . "&action=$lock_unlock$tree->commonvars\">\n"
- . '<img src="'.$CFG->pixpath.'/t/'.$lock_unlock.'.gif" class="iconsmall" alt="'
- . ${'str' . $lock_unlock}.'" title="'.${'str' . $lock_unlock}.'" /></a>'. "\n";
-
- // Prepare expand/contract string
- $expand_contract = 'switch_minus'; // Default: expanded
- $state = get_user_preferences('grade_category_' . $object->id, GRADE_CATEGORY_EXPANDED);
- if ($state == GRADE_CATEGORY_CONTRACTED) {
- $expand_contract = 'switch_plus';
- }
-
- $contract_expand_icon = '<a href="report.php?report=grader&target=' . $eid
- . "&action=$expand_contract$tree->commonvars\">\n"
- . '<img src="'.$CFG->pixpath.'/t/'.$expand_contract.'.gif" class="iconsmall" alt="'
- . ${'str' . $expand_contract}.'" title="'.${'str' . $expand_contract}.'" /></a>'. "\n";
-
- // If an array of icon names is given, return only these in the order they are given
- if (!empty($icons) && is_array($icons)) {
- $new_html = '';
-
- foreach ($icons as $icon_name) {
- if ($icon_name == 'edit') {
- $icon_name .= "_$type";
- }
- if ($limit) {
- $new_html .= ${$icon_name . '_icon'};
- } else {
- ${'show_' . $icon_name} = false;
- }
- }
- if ($limit) {
- return $new_html;
- } else {
- $html .= $new_html;
- }
- }
-
- // Icons shown when edit mode is on
- if ($USER->gradeediting) {
- // Edit icon (except for grade_grades)
- if ($type == 'category') {
- $html .= $edit_category_icon;
-
- } else if ($type == 'item' or $type == 'courseitem' or $type == 'categoryitem') {
- $html .= $edit_item_icon;
- }
-
- // Calculation icon for items and categories
- if ($showcalculations && $type != 'grade') {
- $html .= $edit_calculation_icon;
- }
-
- if ($showeyecons) {
- $html .= $show_hide_icon;
- }
-
- if ($showlocks) {
- $html .= $lock_unlock_icon;
- }
-
- // If object is a category, display expand/contract icon
- if (get_class($object) == 'grade_category' && $aggregationview == GRADER_REPORT_AGGREGATION_VIEW_COMPACT) {
- $html .= $contract_expand_icon;
- }
- } else { // Editing mode is off
- }
-
- return $html . '</div>';
-}
-
?>
if (has_capability('moodle/notes:manage', $context) || has_capability('moodle/notes:view', $context)) {
$output .= '<a href="'.$CFG->wwwroot.'/notes/index.php?course=' . $course->id. '&user='.$user->id.'">'.get_string('notes','notes').'</a><br />';
}
-
+
if (has_capability('moodle/site:viewreports', $context)) {
$timemidnight = usergetmidnight(time());
$output .= '<a href="'. $CFG->wwwroot .'/course/user.php?id='. $course->id .'&user='. $user->id .'">'. $string->activity .'</a><br />';
}
-/**
+/**
* Returns an image of an up or down arrow, used for column sorting. To avoid unnecessary DB accesses, please
* provide this function with the language strings for sortasc and sortdesc.
* If no sort string is associated with the direction, an arrow with no alt text will be printed/returned.
* @param string $strsort The language string used for the alt attribute of this image
* @param bool $return Whether to print directly or return the html string
* @return string HTML for the image
- *
+ *
* TODO See if this isn't already defined somewhere. If not, move this to weblib
*/
function print_arrow($direction='up', $strsort=null, $return=false) {
global $CFG;
-
+
if (!in_array($direction, array('up', 'down', 'right', 'left'))) {
return null;
}
-
- $return = null;
+
+ $return = null;
switch ($direction) {
case 'up':