From 5528217eda9c72766ccc9f2db4f013f3494f35f0 Mon Sep 17 00:00:00 2001 From: nicolasconnault Date: Wed, 25 Feb 2009 07:56:11 +0000 Subject: [PATCH] MDL-17991 Implementing user report improvements --- grade/report/user/lib.php | 354 +++++++++++++++++++++-------------- grade/report/user/styles.php | 110 ++++++++++- 2 files changed, 316 insertions(+), 148 deletions(-) diff --git a/grade/report/user/lib.php b/grade/report/user/lib.php index 03ff9f60be5..49ba8a61d70 100644 --- a/grade/report/user/lib.php +++ b/grade/report/user/lib.php @@ -64,6 +64,22 @@ class grade_report_user extends grade_report { */ public $showpercentage; + /** + * Show range + */ + var $showrange; + + var $tableheaders; + var $tablecolumns; + + var $maxdepth; + var $evenodd; + + var $tabledata; + var $canviewhidden; + + var $switch; + /** * Show hidden items even when user does not have required cap */ @@ -83,11 +99,24 @@ class grade_report_user extends grade_report { $this->showrank = grade_get_setting($this->courseid, 'report_user_showrank', $CFG->grade_report_user_showrank); $this->showpercentage = grade_get_setting($this->courseid, 'report_user_showpercentage', $CFG->grade_report_user_showpercentage); $this->showhiddenitems = grade_get_setting($this->courseid, 'report_user_showhiddenitems', $CFG->grade_report_user_showhiddenitems); + $this->showrange = true; - $switch = grade_get_setting($this->courseid, 'aggregationposition', $CFG->grade_aggregationposition); + $this->switch = grade_get_setting($this->courseid, 'aggregationposition', $CFG->grade_aggregationposition); - // Grab the grade_seq for this course - $this->gseq = new grade_seq($this->courseid, $switch); + // Grab the grade_tree for this course + $this->gtree = new grade_tree($this->courseid, false, $this->switch, false, true); + + // Determine the number of rows and indentation + $this->maxdepth = 1; + $this->inject_rowspans($this->gtree->top_element); + $this->maxdepth++; // Need to account for the lead column that spans all children + for ($i = 1; $i <= $this->maxdepth; $i++) { + $this->evenodd[$i] = 0; + } + + $this->tabledata = array(); + + $this->canviewhidden = has_capability('moodle/grade:viewhidden', get_context_instance(CONTEXT_COURSE, $this->courseid)); // get the user (for full name) $this->user = $DB->get_record('user', array('id' => $userid)); @@ -100,6 +129,22 @@ class grade_report_user extends grade_report { $this->setup_table(); } + function inject_rowspans(&$element) { + if ($element['depth'] > $this->maxdepth) { + $this->maxdepth = $element['depth']; + } + if (empty($element['children'])) { + return 1; + } + $count = 1; + foreach ($element['children'] as $key=>$child) { + $count += $this->inject_rowspans($element['children'][$key]); + } + $element['rowspan'] = $count; + return $count; + } + + /** * Prepares the headers and attributes of the flexitable. */ @@ -111,170 +156,131 @@ class grade_report_user extends grade_report { */ // setting up table headers - $tablecolumns = array('itemname', 'category', 'grade'); - $tableheaders = array($this->get_lang_string('gradeitem', 'grades'), - $this->get_lang_string('category'), + $this->tablecolumns = array('itemname', 'grade'); + $this->tableheaders = array($this->get_lang_string('gradeitem', 'grades'), $this->get_lang_string('grade')); + if ($this->showrange) { + $this->tablecolumns[] = 'range'; + $this->tableheaders[] = $this->get_lang_string('range', 'grades'); + } + if ($this->showpercentage) { - $tablecolumns[] = 'percentage'; - $tableheaders[] = $this->get_lang_string('percentage', 'grades'); + $this->tablecolumns[] = 'percentage'; + $this->tableheaders[] = $this->get_lang_string('percentage', 'grades'); } if ($this->showrank) { // TODO: this is broken if hidden grades present!! - $tablecolumns[] = 'rank'; - $tableheaders[] = $this->get_lang_string('rank', 'grades'); + $this->tablecolumns[] = 'rank'; + $this->tableheaders[] = $this->get_lang_string('rank', 'grades'); } - $tablecolumns[] = 'feedback'; - $tableheaders[] = $this->get_lang_string('feedback', 'grades'); + $this->tablecolumns[] = 'feedback'; + $this->tableheaders[] = $this->get_lang_string('feedback', 'grades'); - $this->table = new flexible_table('grade-report-user-'.$this->courseid); - - $this->table->define_columns($tablecolumns); - $this->table->define_headers($tableheaders); - $this->table->define_baseurl($this->baseurl); - - $this->table->set_attribute('cellspacing', '0'); - $this->table->set_attribute('class', 'user-grades boxaligncenter generaltable'); - - // not sure tables should be sortable or not, because if we allow it then sorted results distort grade category structure and sortorder - $this->table->set_control_variables(array( - TABLE_VAR_SORT => 'ssort', - TABLE_VAR_HIDE => 'shide', - TABLE_VAR_SHOW => 'sshow', - TABLE_VAR_IFIRST => 'sifirst', - TABLE_VAR_ILAST => 'silast', - TABLE_VAR_PAGE => 'spage' - )); - - $this->table->setup(); } - public function fill_table() { - global $CFG, $DB; - $numusers = $this->get_numusers(false); // total course users - $items =& $this->gseq->items; - $grades = array(); + function fill_table() { + //print "
";
+        //print_r($this->gtree->top_element);
+        $this->fill_table_recursive($this->gtree->top_element);
+        //print_r($this->tabledata);
+        //print "
"; + return true; + } - $canviewhidden = has_capability('moodle/grade:viewhidden', get_context_instance(CONTEXT_COURSE, $this->courseid)); + private function fill_table_recursive(&$element) { + global $CFG; - // fetch or create all grades - foreach ($items as $key=>$unused) { - if (!$grade_grade = grade_grade::fetch(array('itemid'=>$items[$key]->id, 'userid'=>$this->user->id))) { + $type = $element['type']; + $depth = $element['depth']; + $grade_object = $element['object']; + $eid = $grade_object->id; + $fullname = $this->gtree->get_element_header($element, true, true, true); + $data = array(); + $hidden = ''; + $excluded = ''; + $class = ''; + + + if ($type == 'category') { + $this->evenodd[$depth] = (($this->evenodd[$depth] + 1) % 2); + } + $alter = ($this->evenodd[$depth] == 0) ? 'even' : 'odd'; + + /// Process those items that have scores associated + if ($type == 'item' or $type == 'categoryitem' or $type == 'courseitem') { + if (! $grade_grade = grade_grade::fetch(array('itemid'=>$grade_object->id,'userid'=>$this->user->id))) { $grade_grade = new grade_grade(); $grade_grade->userid = $this->user->id; - $grade_grade->itemid = $items[$key]->id; - } - $grades[$key] = $grade_grade; - $grades[$key]->grade_item =& $items[$key]; - } - - if ($canviewhidden) { - $altered = array(); - $unknown = array(); - } else { - $hiding_affected = grade_grade::get_hiding_affected($grades, $items); - $altered = $hiding_affected['altered']; - $unknown = $hiding_affected['unknown']; - unset($hiding_affected); - } - - foreach ($items as $itemid=>$unused) { - $grade_item =& $items[$itemid]; - $grade_grade =& $grades[$itemid]; - - if (!$canviewhidden and $grade_item->is_hidden()) { - if ($this->showhiddenitems == 0) { - // no hidden items at all - continue; - } else if ($this->showhiddenitems == 1 and !$grade_item->is_hiddenuntil()) { - // hidden until that are still hidden are visible - continue; - } + $grade_grade->itemid = $grade_object->id; } - $class = 'gradeitem'; - if ($grade_item->is_course_item()) { - $class = 'courseitem'; - } else if ($grade_item->is_category_item()) { - $class = 'categoryitem'; + $grade_grade->load_grade_item(); + + /// Hidden Items + if ($grade_grade->grade_item->is_hidden()) { + $hidden = ' hidden'; } - if (in_array($itemid, $unknown)) { - $gradeval = null; - } else if (array_key_exists($itemid, $altered)) { - $gradeval = $altered[$itemid]; - } else { - $gradeval = $grade_grade->finalgrade; - } - - $data = array(); - - // all users should know which items are still hidden - $hidden = ''; - if ($grade_item->is_hidden()) { - $hidden = ' hidden '; - } - - $element = $this->gseq->locate_element($this->gseq->get_item_eid($grade_item)); - $header = $this->gseq->get_element_header($element, true, true, true); - - /// prints grade item name - $data[] = ''.$header.''; - - /// prints category - $cat = $grade_item->get_parent_category(); - $data[] = ''.$cat->get_name().''; - - $hidden = ''; - if ($grade_item->is_hidden()) { - // can not see grades in hidden items - $hidden = ' hidden '; - } else if ($canviewhidden and $grade_grade->is_hidden()) { - // if user can see hidden grades, indicate which ones are hidden - $hidden = ' hidden '; - } - - /// prints the grade + /// Excluded Item if ($grade_grade->is_excluded()) { - $excluded = get_string('excluded', 'grades').' '; - } else { - $excluded = ''; + $fullname .= ' ['.get_string('excluded', 'grades').']'; + $excluded = ' excluded'; } - if ($grade_item->needsupdate) { - $data[] = ''.get_string('error').''; + /// Other class information + $class = "$hidden $excluded"; + if ($this->switch) { // alter style based on whether aggregation is first or last + $class .= ($type == 'categoryitem' or $type == 'courseitem') ? " ".$alter."d$depth baggt b2b" : " item b1b"; + } else { + $class .= ($type == 'categoryitem' or $type == 'courseitem') ? " ".$alter."d$depth baggb" : " item b1b"; + } - } else if (!empty($CFG->grade_hiddenasdate) and $grade_grade->get_datesubmitted() and !$canviewhidden and $grade_grade->is_hidden() - and !$grade_item->is_category_item() and !$grade_item->is_course_item()) { + /// Name + $data['itemname']['content'] = $fullname; + $data['itemname']['class'] = $class; + $data['itemname']['colspan'] = ($this->maxdepth - $depth); + + /// Actual Grade + $gradeval = $grade_grade->finalgrade; + if ($grade_grade->grade_item->needsupdate) { + $data['grade']['class'] = $class.' gradingerror'; + $data['grade']['content'] = get_string('error'); + } else if (!empty($CFG->grade_hiddenasdate) and $grade_grade->get_datesubmitted() and !$this->canviewhidden and $grade_grade->is_hidden() + and !$grade_grade->grade_item->is_category_item() and !$grade_grade->grade_item->is_course_item()) { // the problem here is that we do not have the time when grade value was modified, 'timemodified' is general modification date for grade_grades records - $data[] = ''.$excluded.get_string('submittedon', 'grades', userdate($grade_grade->get_datesubmitted(), get_string('strftimedatetimeshort'))).''; + $class .= ' datesubmitted'; + $data['grade']['class'] = $class; + $data['grade']['content'] = get_string('submittedon', 'grades', userdate($grade_grade->get_datesubmitted(), get_string('strftimedatetimeshort'))); } else { - $data[] = ''.$excluded.grade_format_gradevalue($gradeval, $grade_item, true).''; + $data['grade']['class'] = $class; + $data['grade']['content'] = grade_format_gradevalue($gradeval, $grade_grade->grade_item, true); } - /// prints percentage + /// Percentage if ($this->showpercentage) { - if ($grade_item->needsupdate) { - $data[] = ''.get_string('error').''; - + if ($grade_grade->grade_item->needsupdate) { + $data['percentage']['class'] = $class.' gradingerror'; + $data['percentage']['content'] = get_string('error'); } else { - $data[] = ''.grade_format_gradevalue($gradeval, $grade_item, true, GRADE_DISPLAY_TYPE_PERCENTAGE).''; + $data['percentage']['class'] = $class; + $data['percentage']['content'] = grade_format_gradevalue($gradeval, $grade_grade->grade_item, true, GRADE_DISPLAY_TYPE_PERCENTAGE); } } - /// prints rank + /// Rank if ($this->showrank) { // TODO: this is broken if hidden grades present!! - if ($grade_item->needsupdate) { - $data[] = ''.get_string('error').''; - + if ($grade_grade->grade_item->needsupdate) { + $data['rank']['class'] = $class.' gradingerror'; + $data['rank']['content'] = get_string('error'); } else if (is_null($gradeval)) { // no grade, no rank - $data[] = '-';; + $data['rank']['class'] = $class; + $data['rank']['content'] = '-'; } else { /// find the number of users with a higher grade @@ -284,22 +290,51 @@ class grade_report_user extends grade_report { AND itemid = ?"; $rank = $DB->count_records_sql($sql, array($grade_grade->finalgrade, $grade_item->id)) + 1; - $data[] = ''."$rank/$numusers".''; + $data['rank']['class'] = $class; + $data['rank']['content'] = "$rank/".$this->get_numusers(false); // total course users } } - /// prints feedback - if (empty($grade_grade->feedback) or (!$canviewhidden and $grade_grade->is_hidden())) { - $data[] = '
 
'; + /// Feedback + if (empty($grade_grade->feedback) or (!$this->canviewhidden and $grade_grade->is_hidden())) { + $data['feedback']['class'] = $class.' feedbacktext'; + $data['feedback']['content'] = ' '; } else { - $data[] = '
'.format_text($grade_grade->feedback, $grade_grade->feedbackformat).'
'; + $data['feedback']['class'] = $class.' feedbacktext'; + $data['feedback']['content'] = format_text($grade_grade->feedback, $grade_grade->feedbackformat); } - $this->table->add_data($data); + /// Range + if ($this->showrange) { + $data['range']['class'] = $class; + $data['range']['content'] = $grade_grade->grade_item->get_formatted_range(); + } } - return true; + /// Category + if ($type == 'category') { + $data['leader']['class'] = $class.' '.$alter."d$depth b1t b2b b1l"; + $data['leader']['rowspan'] = $element['rowspan']; + + if ($this->switch) { // alter style based on whether aggregation is first or last + $data['itemname']['class'] = $class.' '.$alter."d$depth b1b b1t"; + } else { + $data['itemname']['class'] = $class.' '.$alter."d$depth b2t"; + } + $data['itemname']['colspan'] = ($this->maxdepth - $depth + count($this->tablecolumns) - 1); + $data['itemname']['content'] = $fullname; + } + + /// Add this row to the overall system + $this->tabledata[] = $data; + + /// Recursively iterate through all child elements + if (isset($element['children'])) { + foreach ($element['children'] as $key=>$child) { + $this->fill_table_recursive($element['children'][$key]); + } + } } /** @@ -308,9 +343,46 @@ class grade_report_user extends grade_report { * @return string */ public function print_table($return=false) { - ob_start(); - $this->table->print_html(); - $html = ob_get_clean(); + $maxspan = $this->maxdepth; + + /// Build table structure + $html = " + + + + \n"; + + for ($i = 1; $i < count($this->tableheaders); $i++) { + $html .= "\n"; + } + + $html .= " + + + \n"; + + /// Print out the table data + for ($i = 0; $i < count($this->tabledata); $i++) { + $html .= "\n"; + if (isset($this->tabledata[$i]['leader'])) { + $rowspan = $this->tabledata[$i]['leader']['rowspan']; + $class = $this->tabledata[$i]['leader']['class']; + $html .= "\n"; + } + for ($j = 0; $j < count($this->tablecolumns); $j++) { + $name = $this->tablecolumns[$j]; + $class = (isset($this->tabledata[$i][$name]['class'])) ? $this->tabledata[$i][$name]['class'] : ''; + $colspan = (isset($this->tabledata[$i][$name]['colspan'])) ? "colspan='".$this->tabledata[$i][$name]['colspan']."'" : ''; + $content = (isset($this->tabledata[$i][$name]['content'])) ? $this->tabledata[$i][$name]['content'] : null; + if (isset($content)) { + $html .= "\n"; + } + } + $html .= "\n"; + } + + $html .= "
".$this->tableheaders[0]."".$this->tableheaders[$i]."
$content
"; + if ($return) { return $html; } else { @@ -347,9 +419,9 @@ function grade_report_user_settings_definition(&$mform) { $mform->setHelpButton('report_user_showrank', array('showrank', get_string('showrank', 'grades'), 'grade')); if (empty($CFG->grade_report_user_showpercentage)) { - $options[-1] = get_string('defaultprev', 'grades', $options[1]); - } else { $options[-1] = get_string('defaultprev', 'grades', $options[0]); + } else { + $options[-1] = get_string('defaultprev', 'grades', $options[1]); } $mform->addElement('select', 'report_user_showpercentage', get_string('showpercentage', 'grades'), $options); diff --git a/grade/report/user/styles.php b/grade/report/user/styles.php index 9dd3d174f5b..92e5f0d6dcf 100644 --- a/grade/report/user/styles.php +++ b/grade/report/user/styles.php @@ -1,14 +1,13 @@ - -.grade-report-user table.user-grades .datesubmitted { +.grade-report-user table#user-grade .datesubmitted { font-size: 0.7em; } -.grade-report-user table.user-grades .courseitem, -.grade-report-user table.user-grades .categoryitem { +.grade-report-user table#user-grade .courseitem, +.grade-report-user table#user-grade .categoryitem { font-weight: bold; } -.grade-report-user table.user-grades td.cell { +.grade-report-user table#user-grade td.cell { padding-left: 5px; padding-right: 5px; } @@ -19,7 +18,104 @@ } /* this must be last if we want to override other category and course item colors */ -.grade-report-user table.user-grades .hidden, -.grade-report-user table.user-grades .hidden a { +.grade-report-user table#user-grade .hidden, +.grade-report-user table#user-grade .hidden a { color:#aaaaaa; } + +table#user-grade { + border: 1px solid black; + margin: auto; + padding: 0.25em; + font-size: 0.8em; +} +table#user-grade td { + margin: 1px; + padding: 0.25em; +} +table#user-grade thead { + border-bottom: 3px double black; +} +table#user-grade thead th { + padding: 0.25em 0.75em 0.25em 0.75em; +} + +table#user-grade td.oddd1 { + background-color: #f3dfd0; +} +table#user-grade td.oddd2 { + background-color: #d0dbf3; +} +table#user-grade td.oddd3 { + background-color: #d0f3d6; +} +table#user-grade td.oddd4 { + background-color: #f0f0aa; +} + +table#user-grade td.evend2 { + background-color: #b0bbd3; +} +table#user-grade td.evend3 { + background-color: #b0dfb6; +} +table#user-grade td.evend4 { + background-color: #cac8be; +} + +table#user-grade td.b1t { + border-top: 1px solid black; +} +table#user-grade td.b1r { + border-right: 1px solid black; +} +table#user-grade td.b1b { + border-bottom: 1px solid black; +} +table#user-grade td.b1l { + border-left: 1px solid black; +} + +table#user-grade td.b2t { + border-top: 2px solid black; +} +table#user-grade td.b2r { + border-right: 2px solid black; +} +table#user-grade td.b2b { + border-bottom: 2px solid black; +} +table#user-grade td.b2l { + border-left: 2px solid black; +} + +table#user-grade td.baggt, +table#user-grade td.baggb { + font-style: italic; + font-weight: bold; +} +table#user-grade td.baggt { + border-top: 3px double black; +} +table#user-grade td.baggb { + border-bottom: 3px double black; +} + +table#user-grade td.item { + border-left: 1px solid gray; + border-right: 1px solid gray; +} +table#user-grade td.excluded { + /*text-decoration: line-through;*/ + background-color: #666; +} +table#user-grade td.hidden { + color: #aaa; +} + +table#user-grade td { + min-width: 0.5em; + vertical-align: top; +} + +