Commit | Line | Data |
---|---|---|
e060e33d | 1 | <?php |
2 | ||
3 | // This file is part of Moodle - http://moodle.org/ | |
4 | // | |
5 | // Moodle is free software: you can redistribute it and/or modify | |
6 | // it under the terms of the GNU General Public License as published by | |
7 | // the Free Software Foundation, either version 3 of the License, or | |
8 | // (at your option) any later version. | |
9 | // | |
10 | // Moodle is distributed in the hope that it will be useful, | |
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | // GNU General Public License for more details. | |
14 | // | |
15 | // You should have received a copy of the GNU General Public License | |
16 | // along with Moodle. If not, see <http://www.gnu.org/licenses/>. | |
8ad36f4c | 17 | |
4ba9941c | 18 | /** |
19 | * File in which the grader_report class is defined. | |
20 | * @package gradebook | |
21 | */ | |
22 | ||
eea6690a | 23 | require_once($CFG->dirroot . '/grade/report/lib.php'); |
4ba9941c | 24 | require_once($CFG->libdir.'/tablelib.php'); |
4ba9941c | 25 | |
26 | /** | |
27 | * Class providing an API for the grader report building and displaying. | |
eea6690a | 28 | * @uses grade_report |
4ba9941c | 29 | * @package gradebook |
30 | */ | |
eea6690a | 31 | class grade_report_grader extends grade_report { |
4ba9941c | 32 | /** |
33 | * The final grades. | |
b89a70ce | 34 | * @var array $grades |
4ba9941c | 35 | */ |
d24832f9 | 36 | public $grades; |
4ba9941c | 37 | |
38 | /** | |
39 | * Array of errors for bulk grades updating. | |
40 | * @var array $gradeserror | |
41 | */ | |
d24832f9 | 42 | public $gradeserror = array(); |
4ba9941c | 43 | |
4ba9941c | 44 | //// SQL-RELATED |
45 | ||
4ba9941c | 46 | /** |
47 | * The id of the grade_item by which this report will be sorted. | |
48 | * @var int $sortitemid | |
49 | */ | |
d24832f9 | 50 | public $sortitemid; |
4ba9941c | 51 | |
52 | /** | |
53 | * Sortorder used in the SQL selections. | |
54 | * @var int $sortorder | |
55 | */ | |
d24832f9 | 56 | public $sortorder; |
4ba9941c | 57 | |
58 | /** | |
59 | * An SQL fragment affecting the search for users. | |
60 | * @var string $userselect | |
61 | */ | |
d24832f9 | 62 | public $userselect; |
63 | ||
64 | /** | |
65 | * The bound params for $userselect | |
319770d7 | 66 | * @var array $userselectparams |
d24832f9 | 67 | */ |
319770d7 | 68 | public $userselectparams = array(); |
4ba9941c | 69 | |
4faf5f99 | 70 | /** |
384960dd | 71 | * List of collapsed categories from user preference |
4faf5f99 | 72 | * @var array $collapsed |
73 | */ | |
d24832f9 | 74 | public $collapsed; |
4faf5f99 | 75 | |
66ef0471 | 76 | /** |
77 | * A count of the rows, used for css classes. | |
78 | * @var int $rowcount | |
79 | */ | |
d24832f9 | 80 | public $rowcount = 0; |
66ef0471 | 81 | |
6cc3e350 | 82 | /** |
57068674 | 83 | * Capability check caching |
84 | * */ | |
d24832f9 | 85 | public $canviewhidden; |
57068674 | 86 | |
319770d7 | 87 | var $preferencespage=false; |
653a8648 | 88 | |
4ba9941c | 89 | /** |
90 | * Constructor. Sets local copies of user preferences and initialises grade_tree. | |
91 | * @param int $courseid | |
d30c4481 | 92 | * @param object $gpr grade plugin return tracking object |
eea6690a | 93 | * @param string $context |
94 | * @param int $page The current page being viewed (when report is paged) | |
95 | * @param int $sortitemid The id of the grade_item by which to sort the table | |
4ba9941c | 96 | */ |
d24832f9 | 97 | public function __construct($courseid, $gpr, $context, $page=null, $sortitemid=null) { |
4ba9941c | 98 | global $CFG; |
d24832f9 | 99 | parent::__construct($courseid, $gpr, $context, $page); |
4ba9941c | 100 | |
57068674 | 101 | $this->canviewhidden = has_capability('moodle/grade:viewhidden', get_context_instance(CONTEXT_COURSE, $this->course->id)); |
102 | ||
4faf5f99 | 103 | // load collapsed settings for this report |
104 | if ($collapsed = get_user_preferences('grade_report_grader_collapsed_categories')) { | |
105 | $this->collapsed = unserialize($collapsed); | |
4faf5f99 | 106 | } else { |
384960dd | 107 | $this->collapsed = array('aggregatesonly' => array(), 'gradesonly' => array()); |
4faf5f99 | 108 | } |
384960dd | 109 | |
aea4df41 | 110 | if (empty($CFG->enableoutcomes)) { |
111 | $nooutcomes = false; | |
112 | } else { | |
113 | $nooutcomes = get_user_preferences('grade_report_shownooutcomes'); | |
114 | } | |
115 | ||
e0724506 | 116 | // if user report preference set or site report setting set use it, otherwise use course or site setting |
117 | $switch = $this->get_pref('aggregationposition'); | |
05766b50 | 118 | if ($switch == '') { |
e0724506 | 119 | $switch = grade_get_setting($this->courseid, 'aggregationposition', $CFG->grade_aggregationposition); |
120 | } | |
121 | ||
4faf5f99 | 122 | // Grab the grade_tree for this course |
e0724506 | 123 | $this->gtree = new grade_tree($this->courseid, true, $switch, $this->collapsed, $nooutcomes); |
4faf5f99 | 124 | |
4ba9941c | 125 | $this->sortitemid = $sortitemid; |
126 | ||
4ba9941c | 127 | // base url for sorting by first/last name |
09cef06a | 128 | |
319770d7 | 129 | $this->baseurl = new moodle_url('index.php', array('id' => $this->courseid)); |
130 | ||
131 | $studentsperpage = $this->get_pref('studentsperpage'); | |
09cef06a | 132 | if (!empty($studentsperpage)) { |
319770d7 | 133 | $this->baseurl->params(array('perpage' => $studentsperpage, 'page' => $this->page)); |
09cef06a | 134 | } |
09cef06a | 135 | |
319770d7 | 136 | $this->pbarurl = new moodle_url('index.php', array('id' => $this->courseid, 'perpage' => $studentsperpage)); |
4ba9941c | 137 | |
35079f53 | 138 | $this->setup_groups(); |
4ba9941c | 139 | |
140 | $this->setup_sortitemid(); | |
141 | } | |
142 | ||
4ba9941c | 143 | /** |
144 | * Processes the data sent by the form (grades and feedbacks). | |
75674470 | 145 | * Caller is reposible for all access control checks |
146 | * @param array $data form submission (with magic quotes) | |
147 | * @return array empty array if success, array of warnings if something fails. | |
4ba9941c | 148 | */ |
d24832f9 | 149 | public function process_data($data) { |
5c75a0a3 | 150 | global $DB; |
75674470 | 151 | $warnings = array(); |
2cc773f5 | 152 | |
30ebb74f | 153 | $separategroups = false; |
154 | $mygroups = array(); | |
155 | if ($this->groupmode == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $this->context)) { | |
156 | $separategroups = true; | |
157 | $mygroups = groups_get_user_groups($this->course->id); | |
158 | $mygroups = $mygroups[0]; // ignore groupings | |
159 | // reorder the groups fro better perf bellow | |
160 | $current = array_search($this->currentgroup, $mygroups); | |
161 | if ($current !== false) { | |
162 | unset($mygroups[$current]); | |
163 | array_unshift($mygroups, $this->currentgroup); | |
164 | } | |
165 | } | |
166 | ||
4ba9941c | 167 | // always initialize all arrays |
168 | $queue = array(); | |
4ba9941c | 169 | foreach ($data as $varname => $postedvalue) { |
4ba9941c | 170 | |
171 | $needsupdate = false; | |
4ba9941c | 172 | |
173 | // skip, not a grade nor feedback | |
79eabc2a | 174 | if (strpos($varname, 'grade') === 0) { |
319770d7 | 175 | $datatype = 'grade'; |
79eabc2a | 176 | } else if (strpos($varname, 'feedback') === 0) { |
319770d7 | 177 | $datatype = 'feedback'; |
4ba9941c | 178 | } else { |
179 | continue; | |
180 | } | |
181 | ||
182 | $gradeinfo = explode("_", $varname); | |
4ba9941c | 183 | $userid = clean_param($gradeinfo[1], PARAM_INT); |
184 | $itemid = clean_param($gradeinfo[2], PARAM_INT); | |
185 | ||
29a5680e | 186 | $oldvalue = $data->{'old'.$varname}; |
187 | ||
188 | // was change requested? | |
99ccfda8 | 189 | if ($oldvalue == $postedvalue) { // string comparison |
29a5680e | 190 | continue; |
191 | } | |
192 | ||
319770d7 | 193 | if (!$gradeitem = grade_item::fetch(array('id'=>$itemid, 'courseid'=>$this->courseid))) { // we must verify course id here! |
14398fd6 | 194 | print_error('invalidgradeitmeid'); |
4ba9941c | 195 | } |
196 | ||
197 | // Pre-process grade | |
319770d7 | 198 | if ($datatype == 'grade') { |
4256a134 | 199 | $feedback = false; |
200 | $feedbackformat = false; | |
319770d7 | 201 | if ($gradeitem->gradetype == GRADE_TYPE_SCALE) { |
4ba9941c | 202 | if ($postedvalue == -1) { // -1 means no grade |
203 | $finalgrade = null; | |
204 | } else { | |
29a5680e | 205 | $finalgrade = $postedvalue; |
4ba9941c | 206 | } |
207 | } else { | |
76317c73 | 208 | $finalgrade = unformat_float($postedvalue); |
4ba9941c | 209 | } |
79eabc2a | 210 | |
0a2c8485 | 211 | $errorstr = ''; |
379ea949 | 212 | // Warn if the grade is out of bounds. |
213 | if (is_null($finalgrade)) { | |
214 | // ok | |
653a8648 | 215 | } else { |
319770d7 | 216 | $bounded = $gradeitem->bounded_grade($finalgrade); |
653a8648 | 217 | if ($bounded > $finalgrade) { |
0a2c8485 | 218 | $errorstr = 'lessthanmin'; |
653a8648 | 219 | } else if ($bounded < $finalgrade) { |
220 | $errorstr = 'morethanmax'; | |
221 | } | |
0a2c8485 | 222 | } |
223 | if ($errorstr) { | |
5c75a0a3 | 224 | $user = $DB->get_record('user', array('id' => $userid), 'id, firstname, lastname'); |
379ea949 | 225 | $gradestr = new object(); |
0a2c8485 | 226 | $gradestr->username = fullname($user); |
319770d7 | 227 | $gradestr->itemname = $gradeitem->get_name(); |
9d35e66e | 228 | $warnings[] = get_string($errorstr, 'grades', $gradestr); |
0a2c8485 | 229 | } |
230 | ||
319770d7 | 231 | } else if ($datatype == 'feedback') { |
4256a134 | 232 | $finalgrade = false; |
79eabc2a | 233 | $trimmed = trim($postedvalue); |
234 | if (empty($trimmed)) { | |
29a5680e | 235 | $feedback = NULL; |
e1d2692a | 236 | } else { |
653a8648 | 237 | $feedback = stripslashes($postedvalue); |
e1d2692a | 238 | } |
4ba9941c | 239 | } |
4ba9941c | 240 | |
30ebb74f | 241 | // group access control |
242 | if ($separategroups) { | |
243 | // note: we can not use $this->currentgroup because it would fail badly | |
244 | // when having two browser windows each with different group | |
245 | $sharinggroup = false; | |
246 | foreach($mygroups as $groupid) { | |
247 | if (groups_is_member($groupid, $userid)) { | |
248 | $sharinggroup = true; | |
249 | break; | |
250 | } | |
251 | } | |
252 | if (!$sharinggroup) { | |
253 | // either group membership changed or somebedy is hacking grades of other group | |
254 | $warnings[] = get_string('errorsavegrade', 'grades'); | |
255 | continue; | |
256 | } | |
257 | } | |
258 | ||
319770d7 | 259 | $gradeitem->update_final_grade($userid, $finalgrade, 'gradebook', $feedback, FORMAT_MOODLE); |
4ba9941c | 260 | } |
261 | ||
75674470 | 262 | return $warnings; |
4ba9941c | 263 | } |
264 | ||
4ba9941c | 265 | |
266 | /** | |
267 | * Setting the sort order, this depends on last state | |
268 | * all this should be in the new table class that we might need to use | |
269 | * for displaying grades. | |
270 | */ | |
d24832f9 | 271 | private function setup_sortitemid() { |
63d6efa2 | 272 | |
273 | global $SESSION; | |
274 | ||
4ba9941c | 275 | if ($this->sortitemid) { |
276 | if (!isset($SESSION->gradeuserreport->sort)) { | |
a80112f0 | 277 | if ($this->sortitemid == 'firstname' || $this->sortitemid == 'lastname') { |
278 | $this->sortorder = $SESSION->gradeuserreport->sort = 'ASC'; | |
279 | } else { | |
280 | $this->sortorder = $SESSION->gradeuserreport->sort = 'DESC'; | |
281 | } | |
4ba9941c | 282 | } else { |
283 | // this is the first sort, i.e. by last name | |
284 | if (!isset($SESSION->gradeuserreport->sortitemid)) { | |
a80112f0 | 285 | if ($this->sortitemid == 'firstname' || $this->sortitemid == 'lastname') { |
d24832f9 | 286 | $this->sortorder = $SESSION->gradeuserreport->sort = 'ASC'; |
a80112f0 | 287 | } else { |
288 | $this->sortorder = $SESSION->gradeuserreport->sort = 'DESC'; | |
289 | } | |
4ba9941c | 290 | } else if ($SESSION->gradeuserreport->sortitemid == $this->sortitemid) { |
291 | // same as last sort | |
292 | if ($SESSION->gradeuserreport->sort == 'ASC') { | |
293 | $this->sortorder = $SESSION->gradeuserreport->sort = 'DESC'; | |
294 | } else { | |
295 | $this->sortorder = $SESSION->gradeuserreport->sort = 'ASC'; | |
296 | } | |
297 | } else { | |
a80112f0 | 298 | if ($this->sortitemid == 'firstname' || $this->sortitemid == 'lastname') { |
299 | $this->sortorder = $SESSION->gradeuserreport->sort = 'ASC'; | |
300 | } else { | |
301 | $this->sortorder = $SESSION->gradeuserreport->sort = 'DESC'; | |
302 | } | |
4ba9941c | 303 | } |
304 | } | |
305 | $SESSION->gradeuserreport->sortitemid = $this->sortitemid; | |
306 | } else { | |
307 | // not requesting sort, use last setting (for paging) | |
308 | ||
309 | if (isset($SESSION->gradeuserreport->sortitemid)) { | |
310 | $this->sortitemid = $SESSION->gradeuserreport->sortitemid; | |
d20737e8 | 311 | }else{ |
312 | $this->sortitemid = 'lastname'; | |
4ba9941c | 313 | } |
d20737e8 | 314 | |
4ba9941c | 315 | if (isset($SESSION->gradeuserreport->sort)) { |
316 | $this->sortorder = $SESSION->gradeuserreport->sort; | |
317 | } else { | |
318 | $this->sortorder = 'ASC'; | |
319 | } | |
320 | } | |
321 | } | |
322 | ||
4ba9941c | 323 | /** |
b50371da | 324 | * pulls out the userids of the users to be display, and sorts them |
4ba9941c | 325 | */ |
d24832f9 | 326 | public function load_users() { |
327 | global $CFG, $DB; | |
b50371da | 328 | |
319770d7 | 329 | list($usql, $gbrparams) = $DB->get_in_or_equal(explode(',', $this->gradebookroles), SQL_PARAMS_NAMED, 'grbr0'); |
4ba9941c | 330 | |
331 | if (is_numeric($this->sortitemid)) { | |
319770d7 | 332 | $params = array_merge(array('gitemid'=>$this->sortitemid), $gbrparams, $this->groupwheresql_params); |
b50371da | 333 | // the MAX() magic is required in order to please PG |
334 | $sort = "MAX(g.finalgrade) $this->sortorder"; | |
09d0ef21 | 335 | |
9d35e66e | 336 | $sql = "SELECT u.id, u.firstname, u.lastname, u.imagealt, u.picture, u.idnumber |
b50371da | 337 | FROM {user} u |
338 | JOIN {role_assignments} ra ON ra.userid = u.id | |
09d0ef21 | 339 | $this->groupsql |
b50371da | 340 | LEFT JOIN {grade_grades} g ON (g.userid = u.id AND g.itemid = :gitemid) |
341 | WHERE ra.roleid $usql AND u.deleted = 0 | |
09d0ef21 | 342 | $this->groupwheresql |
343 | AND ra.contextid ".get_related_contexts_string($this->context)." | |
b50371da | 344 | GROUP BY u.id, u.firstname, u.lastname, u.imagealt, u.picture, u.idnumber |
09d0ef21 | 345 | ORDER BY $sort"; |
346 | ||
4ba9941c | 347 | } else { |
09d0ef21 | 348 | switch($this->sortitemid) { |
349 | case 'lastname': | |
350 | $sort = "u.lastname $this->sortorder, u.firstname $this->sortorder"; break; | |
351 | case 'firstname': | |
352 | $sort = "u.firstname $this->sortorder, u.lastname $this->sortorder"; break; | |
353 | case 'idnumber': | |
354 | default: | |
355 | $sort = "u.idnumber $this->sortorder"; break; | |
c421ad4b | 356 | } |
4ba9941c | 357 | |
319770d7 | 358 | $params = array_merge($gbrparams, $this->groupwheresql_params); |
b50371da | 359 | $sql = "SELECT DISTINCT u.id, u.firstname, u.lastname, u.imagealt, u.picture, u.idnumber |
d24832f9 | 360 | FROM {user} u |
361 | JOIN {role_assignments} ra ON u.id = ra.userid | |
09d0ef21 | 362 | $this->groupsql |
b50371da | 363 | WHERE ra.roleid $usql AND u.deleted = 0 |
09d0ef21 | 364 | $this->groupwheresql |
365 | AND ra.contextid ".get_related_contexts_string($this->context)." | |
366 | ORDER BY $sort"; | |
4ba9941c | 367 | } |
368 | ||
09d0ef21 | 369 | |
d24832f9 | 370 | $this->users = $DB->get_records_sql($sql, $params, $this->get_pref('studentsperpage') * $this->page, $this->get_pref('studentsperpage')); |
09d0ef21 | 371 | |
4ba9941c | 372 | if (empty($this->users)) { |
373 | $this->userselect = ''; | |
374 | $this->users = array(); | |
0a695c36 | 375 | $this->userselect_params = array(); |
4ba9941c | 376 | } else { |
b50371da | 377 | list($usql, $params) = $DB->get_in_or_equal(array_keys($this->users), SQL_PARAMS_NAMED, 'usid0'); |
d24832f9 | 378 | $this->userselect = "AND g.userid $usql"; |
379 | $this->userselect_params = $params; | |
4ba9941c | 380 | } |
381 | ||
382 | return $this->users; | |
383 | } | |
384 | ||
4ba9941c | 385 | /** |
386 | * we supply the userids in this query, and get all the grades | |
387 | * pulls out all the grades, this does not need to worry about paging | |
388 | */ | |
d24832f9 | 389 | public function load_final_grades() { |
390 | global $CFG, $DB; | |
4ba9941c | 391 | |
23207a1a | 392 | // please note that we must fetch all grade_grades fields if we want to contruct grade_grade object from it! |
b50371da | 393 | $params = array_merge(array('courseid'=>$this->courseid), $this->userselect_params); |
b89a70ce | 394 | $sql = "SELECT g.* |
d24832f9 | 395 | FROM {grade_items} gi, |
396 | {grade_grades} g | |
b50371da | 397 | WHERE g.itemid = gi.id AND gi.courseid = :courseid {$this->userselect}"; |
b89a70ce | 398 | |
399 | $userids = array_keys($this->users); | |
4ba9941c | 400 | |
d297269d | 401 | |
d24832f9 | 402 | if ($grades = $DB->get_records_sql($sql, $params)) { |
b89a70ce | 403 | foreach ($grades as $graderec) { |
d24832f9 | 404 | if (in_array($graderec->userid, $userids) and array_key_exists($graderec->itemid, $this->gtree->get_items())) { // some items may not be present!! |
b89a70ce | 405 | $this->grades[$graderec->userid][$graderec->itemid] = new grade_grade($graderec, false); |
d24832f9 | 406 | $this->grades[$graderec->userid][$graderec->itemid]->grade_item =& $this->gtree->get_item($graderec->itemid); // db caching |
b89a70ce | 407 | } |
408 | } | |
409 | } | |
410 | ||
411 | // prefil grades that do not exist yet | |
412 | foreach ($userids as $userid) { | |
d24832f9 | 413 | foreach ($this->gtree->get_items() as $itemid=>$unused) { |
b89a70ce | 414 | if (!isset($this->grades[$userid][$itemid])) { |
415 | $this->grades[$userid][$itemid] = new grade_grade(); | |
478f4322 | 416 | $this->grades[$userid][$itemid]->itemid = $itemid; |
3b34f698 | 417 | $this->grades[$userid][$itemid]->userid = $userid; |
d24832f9 | 418 | $this->grades[$userid][$itemid]->grade_item =& $this->gtree->get_item($itemid); // db caching |
b89a70ce | 419 | } |
4ba9941c | 420 | } |
421 | } | |
422 | } | |
423 | ||
424 | /** | |
425 | * Builds and returns a div with on/off toggles. | |
426 | * @return string HTML code | |
427 | */ | |
d24832f9 | 428 | public function get_toggles_html() { |
319770d7 | 429 | global $CFG, $USER, $COURSE, $OUTPUT; |
aea4df41 | 430 | |
319770d7 | 431 | $html = ''; |
2cc773f5 | 432 | if ($USER->gradeediting[$this->courseid]) { |
433 | if (has_capability('moodle/grade:manage', $this->context) or has_capability('moodle/grade:hide', $this->context)) { | |
319770d7 | 434 | $html .= $this->print_toggle('eyecons'); |
2cc773f5 | 435 | } |
436 | if (has_capability('moodle/grade:manage', $this->context) | |
437 | or has_capability('moodle/grade:lock', $this->context) | |
438 | or has_capability('moodle/grade:unlock', $this->context)) { | |
319770d7 | 439 | $html .= $this->print_toggle('locks'); |
2cc773f5 | 440 | } |
2ca093fa | 441 | if (has_capability('moodle/grade:manage', $this->context)) { |
319770d7 | 442 | $html .= $this->print_toggle('quickfeedback'); |
2ca093fa | 443 | } |
444 | ||
2cc773f5 | 445 | if (has_capability('moodle/grade:manage', $this->context)) { |
319770d7 | 446 | $html .= $this->print_toggle('calculations'); |
2cc773f5 | 447 | } |
4ba9941c | 448 | } |
449 | ||
57068674 | 450 | if ($this->canviewhidden) { |
319770d7 | 451 | $html .= $this->print_toggle('averages'); |
57068674 | 452 | } |
aae94377 | 453 | |
319770d7 | 454 | $html .= $this->print_toggle('ranges'); |
aea4df41 | 455 | if (!empty($CFG->enableoutcomes)) { |
319770d7 | 456 | $html .= $this->print_toggle('nooutcomes'); |
aea4df41 | 457 | } |
319770d7 | 458 | |
459 | return $OUTPUT->container($html, 'grade-report-toggles'); | |
4ba9941c | 460 | } |
461 | ||
462 | /** | |
463 | * Shortcut function for printing the grader report toggles. | |
464 | * @param string $type The type of toggle | |
465 | * @param bool $return Whether to return the HTML string rather than printing it | |
466 | * @return void | |
467 | */ | |
319770d7 | 468 | public function print_toggle($type) { |
e63f88c9 | 469 | global $CFG, $OUTPUT; |
4ba9941c | 470 | |
319770d7 | 471 | $icons = array('eyecons' => 't/hide', |
472 | 'calculations' => 't/calc', | |
473 | 'locks' => 't/lock', | |
474 | 'averages' => 't/mean', | |
475 | 'quickfeedback' => 't/feedback', | |
476 | 'nooutcomes' => 't/outcomes'); | |
4ba9941c | 477 | |
319770d7 | 478 | $prefname = 'grade_report_show' . $type; |
aea4df41 | 479 | |
319770d7 | 480 | if (array_key_exists($prefname, $CFG)) { |
481 | $showpref = get_user_preferences($prefname, $CFG->$prefname); | |
aea4df41 | 482 | } else { |
319770d7 | 483 | $showpref = get_user_preferences($prefname); |
aea4df41 | 484 | } |
4ba9941c | 485 | |
388234f4 | 486 | $strshow = $this->get_lang_string('show' . $type, 'grades'); |
487 | $strhide = $this->get_lang_string('hide' . $type, 'grades'); | |
4ba9941c | 488 | |
319770d7 | 489 | $showhide = 'show'; |
490 | $toggleaction = 1; | |
4ba9941c | 491 | |
319770d7 | 492 | if ($showpref) { |
493 | $showhide = 'hide'; | |
494 | $toggleaction = 0; | |
4ba9941c | 495 | } |
496 | ||
497 | if (array_key_exists($type, $icons)) { | |
319770d7 | 498 | $imagename = $icons[$type]; |
4ba9941c | 499 | } else { |
319770d7 | 500 | $imagename = "t/$type.gif"; |
4ba9941c | 501 | } |
502 | ||
319770d7 | 503 | $string = ${'str' . $showhide}; |
4ba9941c | 504 | |
319770d7 | 505 | $toggleicon = new moodle_action_icon(); |
506 | $toggleicon->image->src = $OUTPUT->old_icon_url($imagename); | |
507 | $toggleicon->image->add_class('iconsmall'); | |
508 | $toggleicon->alt = $string; | |
509 | $toggleicon->title = $string; | |
510 | $toggleicon->link->url = $this->baseurl->out(false, array('toggle' => $toggleaction, 'toggle_type' => $type), false); | |
4ba9941c | 511 | |
319770d7 | 512 | $retval = $OUTPUT->container($OUTPUT->action_icon($toggleicon, 'gradertoggle')); |
4ba9941c | 513 | |
319770d7 | 514 | return $retval; |
4ba9941c | 515 | } |
516 | ||
517 | /** | |
518 | * Builds and returns the HTML code for the headers. | |
519 | * @return string $headerhtml | |
520 | */ | |
d24832f9 | 521 | public function get_headerhtml() { |
319770d7 | 522 | global $CFG, $USER, $OUTPUT; |
4ba9941c | 523 | |
dc482cfa | 524 | $this->rowcount = 0; |
795b745a | 525 | $fixedstudents = $this->is_fixed_students(); |
203b7e2e | 526 | |
527 | if (!$fixedstudents) { | |
528 | $strsortasc = $this->get_lang_string('sortasc', 'grades'); | |
529 | $strsortdesc = $this->get_lang_string('sortdesc', 'grades'); | |
530 | $strfirstname = $this->get_lang_string('firstname'); | |
531 | $strlastname = $this->get_lang_string('lastname'); | |
532 | $showuseridnumber = $this->get_pref('showuseridnumber'); | |
533 | ||
534 | if ($this->sortitemid === 'lastname') { | |
535 | if ($this->sortorder == 'ASC') { | |
536 | $lastarrow = print_arrow('up', $strsortasc, true); | |
537 | } else { | |
538 | $lastarrow = print_arrow('down', $strsortdesc, true); | |
539 | } | |
540 | } else { | |
541 | $lastarrow = ''; | |
542 | } | |
543 | ||
544 | if ($this->sortitemid === 'firstname') { | |
545 | if ($this->sortorder == 'ASC') { | |
546 | $firstarrow = print_arrow('up', $strsortasc, true); | |
547 | } else { | |
548 | $firstarrow = print_arrow('down', $strsortdesc, true); | |
549 | } | |
550 | } else { | |
551 | $firstarrow = ''; | |
552 | } | |
553 | ||
554 | } | |
4ba9941c | 555 | |
4ba9941c | 556 | // Prepare Table Headers |
557 | $headerhtml = ''; | |
558 | ||
d24832f9 | 559 | $numrows = count($this->gtree->get_levels()); |
4ba9941c | 560 | |
319770d7 | 561 | $columnstounset = array(); |
cb7fe7b4 | 562 | |
d24832f9 | 563 | foreach ($this->gtree->get_levels() as $key=>$row) { |
66ef0471 | 564 | $columncount = 0; |
4ba9941c | 565 | if ($key == 0) { |
cb7fe7b4 | 566 | // do not display course grade category |
4ba9941c | 567 | // continue; |
568 | } | |
569 | ||
203b7e2e | 570 | if ($fixedstudents) { |
571 | $headerhtml .= '<tr class="heading_name_row">'; | |
572 | } else { | |
573 | $headerhtml .= '<tr class="heading r'.$this->rowcount++.'">'; | |
574 | if ($key == $numrows - 1) { | |
bb9b58a6 NC |
575 | $colspan = 1; |
576 | if (has_capability('gradereport/user:view', $this->context)) { | |
577 | $colspan++; | |
578 | } | |
579 | $colspan='colspan="'.$colspan.'"'; | |
580 | ||
319770d7 | 581 | $sortfirstname = html_link::make(clone($this->baseurl), $strfirstname); |
582 | $sortfirstname->url->param('sortitemid', 'firstname'); | |
583 | $sortlastname = html_link::make(clone($this->baseurl), $strlastname); | |
584 | $sortlastname->url->param('sortitemid', 'lastname'); | |
bb9b58a6 | 585 | $headerhtml .= '<th '.$colspan.' class="header c'.$columncount++.'" scope="col">' . $OUTPUT->link($sortfirstname) |
319770d7 | 586 | . $firstarrow. '/ ' . $OUTPUT->link($sortlastname) . $lastarrow .'</th>'; |
203b7e2e | 587 | if ($showuseridnumber) { |
588 | if ('idnumber' == $this->sortitemid) { | |
589 | if ($this->sortorder == 'ASC') { | |
590 | $idnumberarrow = print_arrow('up', $strsortasc, true); | |
591 | } else { | |
592 | $idnumberarrow = print_arrow('down', $strsortdesc, true); | |
593 | } | |
594 | } else { | |
595 | $idnumberarrow = ''; | |
596 | } | |
319770d7 | 597 | $sortidnumber = html_link::make(clone($this->baseurl), get_string('idnumber')); |
598 | $sortidnumber->url->param('sortitemid', 'idnumber'); | |
599 | $headerhtml .= '<th class="header cc'.$columncount++.' useridnumber" scope="col">' . $OUTPUT->link($sortidnumber) . $idnumberarrow . '</th>'; | |
203b7e2e | 600 | } |
bb9b58a6 NC |
601 | } else { |
602 | $colspan = 1; | |
603 | if (has_capability('gradereport/user:view', $this->context)) { | |
604 | $colspan++; | |
605 | } | |
203b7e2e | 606 | if ($showuseridnumber) { |
bb9b58a6 | 607 | $colspan++; |
203b7e2e | 608 | } |
609 | ||
bb9b58a6 NC |
610 | $colspan='colspan="'.$colspan.'"'; |
611 | ||
203b7e2e | 612 | $headerhtml .= '<td '.$colspan.'class="cell c'.$columncount++.' topleft"> </td>'; |
613 | ||
614 | if ($showuseridnumber) { | |
615 | $columncount++; | |
616 | } | |
617 | } | |
618 | } | |
4ba9941c | 619 | |
4ba9941c | 620 | |
cb7fe7b4 | 621 | foreach ($row as $columnkey => $element) { |
319770d7 | 622 | $sortlink = clone($this->baseurl); |
2e3987a9 | 623 | if (isset($element['object']->id)) { |
319770d7 | 624 | $sortlink->param('sortitemid', $element['object']->id); |
2e3987a9 | 625 | } |
626 | ||
cb7fe7b4 | 627 | $eid = $element['eid']; |
628 | $object = $element['object']; | |
629 | $type = $element['type']; | |
438a5aa9 | 630 | $categorystate = @$element['categorystate']; |
2e3987a9 | 631 | $itemmodule = null; |
632 | $iteminstance = null; | |
8c5a416e | 633 | |
66ef0471 | 634 | $columnclass = 'c' . $columncount++; |
4ba9941c | 635 | if (!empty($element['colspan'])) { |
636 | $colspan = 'colspan="'.$element['colspan'].'"'; | |
66ef0471 | 637 | $columnclass = ''; |
4ba9941c | 638 | } else { |
639 | $colspan = ''; | |
640 | } | |
641 | ||
642 | if (!empty($element['depth'])) { | |
643 | $catlevel = ' catlevel'.$element['depth']; | |
644 | } else { | |
645 | $catlevel = ''; | |
646 | } | |
647 | ||
cb7fe7b4 | 648 | // Element is a filler |
4ba9941c | 649 | if ($type == 'filler' or $type == 'fillerfirst' or $type == 'fillerlast') { |
66ef0471 | 650 | $headerhtml .= '<th class="'.$columnclass.' '.$type.$catlevel.'" '.$colspan.' scope="col"> </th>'; |
cb7fe7b4 | 651 | } |
652 | // Element is a category | |
4faf5f99 | 653 | else if ($type == 'category') { |
653a8648 | 654 | $headerhtml .= '<th class=" '. $columnclass.' category'.$catlevel.'" '.$colspan.' scope="col">' |
9ecd4386 | 655 | . shorten_text($element['object']->get_name()); |
4faf5f99 | 656 | $headerhtml .= $this->get_collapsing_icon($element); |
4ba9941c | 657 | |
658 | // Print icons | |
2cc773f5 | 659 | if ($USER->gradeediting[$this->courseid]) { |
d30c4481 | 660 | $headerhtml .= $this->get_icons($element); |
4ba9941c | 661 | } |
662 | ||
63d6efa2 | 663 | $headerhtml .= '</th>'; |
cb7fe7b4 | 664 | } |
665 | // Element is a grade_item | |
4faf5f99 | 666 | else { |
2e3987a9 | 667 | $itemmodule = $element['object']->itemmodule; |
668 | $iteminstance = $element['object']->iteminstance; | |
669 | ||
4ba9941c | 670 | if ($element['object']->id == $this->sortitemid) { |
671 | if ($this->sortorder == 'ASC') { | |
319770d7 | 672 | $arrow = $this->get_sort_arrow('up', $sortlink); |
4ba9941c | 673 | } else { |
319770d7 | 674 | $arrow = $this->get_sort_arrow('down', $sortlink); |
4ba9941c | 675 | } |
676 | } else { | |
319770d7 | 677 | $arrow = $this->get_sort_arrow('move', $sortlink); |
4ba9941c | 678 | } |
679 | ||
80fb1cf9 | 680 | $hidden = ''; |
4ba9941c | 681 | if ($element['object']->is_hidden()) { |
80fb1cf9 | 682 | $hidden = ' hidden '; |
4ba9941c | 683 | } |
684 | ||
6cc3e350 | 685 | $headerlink = $this->gtree->get_element_header($element, true, $this->get_pref('showactivityicons'), false); |
653a8648 | 686 | $headerhtml .= '<th class=" '.$columnclass.' '.$type.$catlevel.$hidden.'" scope="col" onclick="set_col(this.cellIndex)">' |
9ecd4386 | 687 | . shorten_text($headerlink) . $arrow; |
688 | $headerhtml .= '</th>'; | |
4ba9941c | 689 | } |
690 | ||
691 | } | |
692 | ||
693 | $headerhtml .= '</tr>'; | |
694 | } | |
695 | return $headerhtml; | |
696 | } | |
697 | ||
698 | /** | |
699 | * Builds and return the HTML rows of the table (grades headed by student). | |
700 | * @return string HTML | |
701 | */ | |
d24832f9 | 702 | public function get_studentshtml() { |
698c31e1 | 703 | global $CFG, $USER, $DB, $OUTPUT; |
d297269d | 704 | |
4ba9941c | 705 | $studentshtml = ''; |
d297269d | 706 | $strfeedback = $this->get_lang_string("feedback"); |
707 | $strgrade = $this->get_lang_string('grade'); | |
18effef4 | 708 | $gradetabindex = 1; |
d297269d | 709 | $numusers = count($this->users); |
203b7e2e | 710 | $showuserimage = $this->get_pref('showuserimage'); |
711 | $showuseridnumber = $this->get_pref('showuseridnumber'); | |
795b745a | 712 | $fixedstudents = $this->is_fixed_students(); |
4ba9941c | 713 | |
388234f4 | 714 | // Preload scale objects for items with a scaleid |
319770d7 | 715 | $scaleslist = array(); |
c0c1e7c2 | 716 | $tabindices = array(); |
d297269d | 717 | |
d24832f9 | 718 | foreach ($this->gtree->get_items() as $item) { |
388234f4 | 719 | if (!empty($item->scaleid)) { |
319770d7 | 720 | $scaleslist[] = $item->scaleid; |
388234f4 | 721 | } |
d297269d | 722 | |
c0c1e7c2 | 723 | $tabindices[$item->id]['grade'] = $gradetabindex; |
724 | $tabindices[$item->id]['feedback'] = $gradetabindex + $numusers; | |
725 | $gradetabindex += $numusers * 2; | |
388234f4 | 726 | } |
319770d7 | 727 | $scalesarray = array(); |
388234f4 | 728 | |
319770d7 | 729 | if (!empty($scaleslist)) { |
730 | $scalesarray = $DB->get_records_list('scale', 'id', $scaleslist); | |
388234f4 | 731 | } |
d24832f9 | 732 | |
319770d7 | 733 | $rowclasses = array(' even ', ' odd '); |
a5b8be62 | 734 | |
319770d7 | 735 | $rowclasses = array(' even ', ' odd '); |
a47d38f2 | 736 | |
4ba9941c | 737 | foreach ($this->users as $userid => $user) { |
b89a70ce | 738 | |
57068674 | 739 | if ($this->canviewhidden) { |
d297269d | 740 | $altered = array(); |
741 | $unknown = array(); | |
b89a70ce | 742 | } else { |
319770d7 | 743 | $hidingaffected = grade_grade::get_hiding_affected($this->grades[$userid], $this->gtree->get_items()); |
744 | $altered = $hidingaffected['altered']; | |
745 | $unknown = $hidingaffected['unknown']; | |
746 | unset($hidingaffected); | |
b89a70ce | 747 | } |
748 | ||
66ef0471 | 749 | $columncount = 0; |
203b7e2e | 750 | if ($fixedstudents) { |
319770d7 | 751 | $studentshtml .= '<tr class="r'.$this->rowcount++ . $rowclasses[$this->rowcount % 2] . '">'; |
203b7e2e | 752 | } else { |
753 | // Student name and link | |
319770d7 | 754 | $userpic = null; |
203b7e2e | 755 | if ($showuserimage) { |
319770d7 | 756 | $userpic = $OUTPUT->container($OUTPUT->user_picture(moodle_user_picture::make($user, $this->courseid)), 'userpic'); |
203b7e2e | 757 | } |
758 | ||
bb9b58a6 NC |
759 | $userreportcell = ''; |
760 | ||
761 | if (has_capability('gradereport/user:view', $this->context)) { | |
762 | $a->user = fullname($user); | |
763 | $strgradesforuser = get_string('gradesforuser', 'grades', $a); | |
764 | $userreporticon = new moodle_action_icon(); | |
765 | $userreporticon->link->url = new moodle_url($CFG->wwwroot.'/grade/report/user/index.php', array('userid' => $user->id, 'id' => $this->course->id)); | |
766 | $userreporticon->image->add_class('iconsmall'); | |
767 | $userreporticon->image->src = $OUTPUT->old_icon_url('t/grades'); | |
768 | $userreporticon->image->alt = $strgradesforuser; | |
769 | $userreportcell = '<th class="userreport">'.$OUTPUT->action_icon($userreporticon).'</th>'; | |
770 | } | |
771 | ||
319770d7 | 772 | $userlink = html_link::make(new moodle_url($CFG->wwwroot.'/user/view.php', array('id' => $user->id, 'course' => $this->course->id)), fullname($user)); |
773 | $studentshtml .= '<tr class="r'.$this->rowcount++ . $rowclasses[$this->rowcount % 2] . '">' | |
774 | .'<th class="c'.$columncount++.' user" scope="row" onclick="set_row(this.parentNode.rowIndex);">'.$userpic | |
bb9b58a6 | 775 | .$OUTPUT->link($userlink).$userreportcell.'</th>'; |
203b7e2e | 776 | |
777 | if ($showuseridnumber) { | |
653a8648 | 778 | $studentshtml .= '<th class="c'.$columncount++.' useridnumber" onclick="set_row(this.parentNode.rowIndex);">'. |
adf541d9 | 779 | $user->idnumber.'</th>'; |
203b7e2e | 780 | } |
781 | ||
782 | } | |
9d35e66e | 783 | |
dc482cfa | 784 | foreach ($this->gtree->items as $itemid=>$unused) { |
785 | $item =& $this->gtree->items[$itemid]; | |
d297269d | 786 | $grade = $this->grades[$userid][$item->id]; |
b89a70ce | 787 | |
e50ce569 | 788 | // Get the decimal points preference for this item |
31a6c06c | 789 | $decimalpoints = $item->get_decimals(); |
4ba9941c | 790 | |
d297269d | 791 | if (in_array($itemid, $unknown)) { |
792 | $gradeval = null; | |
793 | } else if (array_key_exists($itemid, $altered)) { | |
794 | $gradeval = $altered[$itemid]; | |
795 | } else { | |
796 | $gradeval = $grade->finalgrade; | |
797 | } | |
4ba9941c | 798 | |
00374cc5 | 799 | // MDL-11274 |
800 | // Hide grades in the grader report if the current grader doesn't have 'moodle/grade:viewhidden' | |
57068674 | 801 | if (!$this->canviewhidden and $grade->is_hidden()) { |
6cc3e350 | 802 | if (!empty($CFG->grade_hiddenasdate) and $grade->get_datesubmitted() and !$item->is_category_item() and !$item->is_course_item()) { |
d297269d | 803 | // 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 |
319770d7 | 804 | $studentshtml .= '<td class="cell c'.$columncount++.'">' |
805 | . $OUTPUT->span(userdate($grade->get_datesubmitted(),get_string('strftimedatetimeshort')), 'datesubmitted') . '</td>'; | |
bb49f77b | 806 | } else { |
00374cc5 | 807 | $studentshtml .= '<td class="cell c'.$columncount++.'">-</td>'; |
808 | } | |
a5b8be62 | 809 | continue; |
00374cc5 | 810 | } |
811 | ||
2cc773f5 | 812 | // emulate grade element |
d3c3da1b | 813 | $eid = $this->gtree->get_grade_eid($grade); |
814 | $element = array('eid'=>$eid, 'object'=>$grade, 'type'=>'grade'); | |
2cc773f5 | 815 | |
653a8648 | 816 | $cellclasses = 'grade cell c'.$columncount++; |
dff9d94d | 817 | if ($item->is_category_item()) { |
818 | $cellclasses .= ' cat'; | |
b89a70ce | 819 | } |
dff9d94d | 820 | if ($item->is_course_item()) { |
821 | $cellclasses .= ' course'; | |
b89a70ce | 822 | } |
4ba9941c | 823 | if ($grade->is_overridden()) { |
dff9d94d | 824 | $cellclasses .= ' overridden'; |
4ba9941c | 825 | } |
85db09fb | 826 | |
5ebce7bb | 827 | if ($grade->is_excluded()) { |
dc482cfa | 828 | // $cellclasses .= ' excluded'; |
5ebce7bb | 829 | } |
4ba9941c | 830 | |
319770d7 | 831 | $gradetitle = $OUTPUT->container(fullname($user), 'fullname'); |
832 | $gradetitle .= $OUTPUT->container($item->get_name(true), 'itemname'); | |
653a8648 | 833 | |
834 | if (!empty($grade->feedback) && !$USER->gradeediting[$this->courseid]) { | |
319770d7 | 835 | $gradetitle .= $OUTPUT->container(wordwrap(trim(format_string($grade->feedback, $grade->feedbackformat)), 34, '<br/ >'), 'feedback'); |
653a8648 | 836 | } |
837 | ||
319770d7 | 838 | $studentshtml .= '<td class="'.$cellclasses.'" title="'.s($gradetitle).'">'; |
dff9d94d | 839 | |
23207a1a | 840 | if ($grade->is_excluded()) { |
319770d7 | 841 | $studentshtml .= $OUTPUT->span(get_string('excluded', 'grades'), 'excludedfloater'); |
23207a1a | 842 | } |
843 | ||
4ba9941c | 844 | // Do not show any icons if no grade (no record in DB to match) |
d3c3da1b | 845 | if (!$item->needsupdate and $USER->gradeediting[$this->courseid]) { |
2cc773f5 | 846 | $studentshtml .= $this->get_icons($element); |
4ba9941c | 847 | } |
848 | ||
80fb1cf9 | 849 | $hidden = ''; |
850 | if ($grade->is_hidden()) { | |
851 | $hidden = ' hidden '; | |
852 | } | |
6cc3e350 | 853 | |
d24832f9 | 854 | $gradepass = ' gradefail '; |
46e6df89 | 855 | if ($grade->is_passed($item)) { |
856 | $gradepass = ' gradepass '; | |
e6477988 | 857 | } elseif (is_null($grade->is_passed($item))) { |
858 | $gradepass = ''; | |
46e6df89 | 859 | } |
860 | ||
4ba9941c | 861 | // if in editting mode, we need to print either a text box |
862 | // or a drop down (for scales) | |
4ba9941c | 863 | // grades in item of type grade category or course are not directly editable |
d14ae855 | 864 | if ($item->needsupdate) { |
319770d7 | 865 | $studentshtml .= $OUTPUT->span(get_string('error'), "gradingerror$hidden"); |
d14ae855 | 866 | |
2cc773f5 | 867 | } else if ($USER->gradeediting[$this->courseid]) { |
4ba9941c | 868 | |
319770d7 | 869 | if ($item->scaleid && !empty($scalesarray[$item->scaleid])) { |
870 | $scale = $scalesarray[$item->scaleid]; | |
99ccfda8 | 871 | $gradeval = (int)$gradeval; // scales use only integers |
388234f4 | 872 | $scales = explode(",", $scale->scale); |
873 | // reindex because scale is off 1 | |
9d35e66e | 874 | |
914ea002 | 875 | // MDL-12104 some previous scales might have taken up part of the array |
876 | // so this needs to be reset | |
d48ebf97 | 877 | $scaleopt = array(); |
388234f4 | 878 | $i = 0; |
879 | foreach ($scales as $scaleoption) { | |
880 | $i++; | |
881 | $scaleopt[$i] = $scaleoption; | |
882 | } | |
883 | ||
884 | if ($this->get_pref('quickgrading') and $grade->is_editable()) { | |
0658afc9 | 885 | $oldval = empty($gradeval) ? -1 : $gradeval; |
886 | if (empty($item->outcomeid)) { | |
d4795a07 | 887 | $nogradestr = $this->get_lang_string('nograde'); |
0658afc9 | 888 | } else { |
d4795a07 | 889 | $nogradestr = $this->get_lang_string('nooutcome', 'grades'); |
0658afc9 | 890 | } |
29a5680e | 891 | $studentshtml .= '<input type="hidden" name="oldgrade_'.$userid.'_' |
0658afc9 | 892 | .$item->id.'" value="'.$oldval.'"/>'; |
698c31e1 | 893 | $select = html_select::make($scaleopt, 'grade_'.$userid.'_'.$item->id,$gradeval, $nogradestr); |
894 | $select->nothingvalue = '-1'; | |
895 | $select->tabindex = $tabindices[$item->id]['grade']; | |
896 | $studentshtml .= $OUTPUT->select($select); | |
388234f4 | 897 | } elseif(!empty($scale)) { |
4ba9941c | 898 | $scales = explode(",", $scale->scale); |
4ba9941c | 899 | |
388234f4 | 900 | // invalid grade if gradeval < 1 |
99ccfda8 | 901 | if ($gradeval < 1) { |
319770d7 | 902 | $studentshtml .= $OUTPUT->span('-', "gradevalue$hidden$gradepass"); |
4ba9941c | 903 | } else { |
653a8648 | 904 | $gradeval = $grade->grade_item->bounded_grade($gradeval); //just in case somebody changes scale |
319770d7 | 905 | $studentshtml .= $OUTPUT->span($scales[$gradeval-1], "gradevalue$hidden$gradepass"); |
4ba9941c | 906 | } |
388234f4 | 907 | } else { |
908 | // no such scale, throw error? | |
4ba9941c | 909 | } |
79eabc2a | 910 | |
bb384a8e | 911 | } else if ($item->gradetype != GRADE_TYPE_TEXT) { // Value type |
936f1350 | 912 | if ($this->get_pref('quickgrading') and $grade->is_editable()) { |
76317c73 | 913 | $value = format_float($gradeval, $decimalpoints); |
29a5680e | 914 | $studentshtml .= '<input type="hidden" name="oldgrade_'.$userid.'_'.$item->id.'" value="'.$value.'" />'; |
be55a047 | 915 | $studentshtml .= '<input size="6" tabindex="' . $tabindices[$item->id]['grade'] |
319770d7 | 916 | . '" type="text" class="text" title="'. $strgrade .'" name="grade_' |
c0c1e7c2 | 917 | .$userid.'_' .$item->id.'" value="'.$value.'" />'; |
4ba9941c | 918 | } else { |
319770d7 | 919 | $studentshtml .= $OUTPUT->span(format_float($gradeval, $decimalpoints), "gradevalue$hidden$gradepass"); |
4ba9941c | 920 | } |
921 | } | |
922 | ||
923 | ||
924 | // If quickfeedback is on, print an input element | |
2ca093fa | 925 | if ($this->get_pref('showquickfeedback') and $grade->is_editable()) { |
dc482cfa | 926 | |
29a5680e | 927 | $studentshtml .= '<input type="hidden" name="oldfeedback_' |
928 | .$userid.'_'.$item->id.'" value="' . s($grade->feedback) . '" />'; | |
be55a047 | 929 | $studentshtml .= '<input class="quickfeedback" tabindex="' . $tabindices[$item->id]['feedback'] |
930 | . '" size="6" title="' . $strfeedback . '" type="text" name="feedback_' | |
29a5680e | 931 | .$userid.'_'.$item->id.'" value="' . s($grade->feedback) . '" />'; |
4ba9941c | 932 | } |
933 | ||
78a2d9f0 | 934 | } else { // Not editing |
41f22daa | 935 | $gradedisplaytype = $item->get_displaytype(); |
e50ce569 | 936 | |
78a2d9f0 | 937 | // If feedback present, surround grade with feedback tooltip: Open span here |
4ba9941c | 938 | |
d14ae855 | 939 | if ($item->needsupdate) { |
319770d7 | 940 | $studentshtml .= $OUTPUT->span(get_string('error'), "gradingerror$hidden$gradepass"); |
4ba9941c | 941 | } else { |
319770d7 | 942 | $studentshtml .= $OUTPUT->span(grade_format_gradevalue($gradeval, $item, true, $gradedisplaytype, null), "gradevalue$hidden$gradepass"); |
4ba9941c | 943 | } |
4ba9941c | 944 | } |
945 | ||
946 | if (!empty($this->gradeserror[$item->id][$userid])) { | |
947 | $studentshtml .= $this->gradeserror[$item->id][$userid]; | |
948 | } | |
949 | ||
950 | $studentshtml .= '</td>' . "\n"; | |
951 | } | |
952 | $studentshtml .= '</tr>'; | |
953 | } | |
954 | return $studentshtml; | |
955 | } | |
956 | ||
dc482cfa | 957 | function get_studentnameshtml() { |
1c1f64a2 | 958 | global $CFG, $USER, $OUTPUT; |
dc482cfa | 959 | $studentshtml = ''; |
960 | ||
961 | $showuserimage = $this->get_pref('showuserimage'); | |
962 | $showuseridnumber = $this->get_pref('showuseridnumber'); | |
795b745a | 963 | $fixedstudents = $this->is_fixed_students(); |
dc482cfa | 964 | |
965 | $strsortasc = $this->get_lang_string('sortasc', 'grades'); | |
966 | $strsortdesc = $this->get_lang_string('sortdesc', 'grades'); | |
967 | $strfirstname = $this->get_lang_string('firstname'); | |
968 | $strlastname = $this->get_lang_string('lastname'); | |
969 | ||
970 | if ($this->sortitemid === 'lastname') { | |
971 | if ($this->sortorder == 'ASC') { | |
972 | $lastarrow = print_arrow('up', $strsortasc, true); | |
973 | } else { | |
974 | $lastarrow = print_arrow('down', $strsortdesc, true); | |
975 | } | |
976 | } else { | |
977 | $lastarrow = ''; | |
978 | } | |
979 | ||
980 | if ($this->sortitemid === 'firstname') { | |
981 | if ($this->sortorder == 'ASC') { | |
982 | $firstarrow = print_arrow('up', $strsortasc, true); | |
983 | } else { | |
984 | $firstarrow = print_arrow('down', $strsortdesc, true); | |
985 | } | |
986 | } else { | |
987 | $firstarrow = ''; | |
988 | } | |
989 | ||
203b7e2e | 990 | if ($fixedstudents) { |
319770d7 | 991 | $fixedcolumntable = new html_table(); |
992 | $fixedcolumntable->id = 'fixed_column'; | |
993 | $fixedcolumntable->add_class('fixed_grades_column'); | |
71297a3f | 994 | $fixedcolumntable->bodyclasses = 'leftbody'; |
dc482cfa | 995 | |
bb9b58a6 NC |
996 | $colspan = 1; |
997 | ||
998 | if (has_capability('gradereport/user:view', $this->context)) { | |
999 | $colspan++; | |
1000 | } | |
1001 | ||
203b7e2e | 1002 | if ($showuseridnumber) { |
bb9b58a6 | 1003 | $colspan++; |
203b7e2e | 1004 | } |
dc482cfa | 1005 | |
203b7e2e | 1006 | $levels = count($this->gtree->levels) - 1; |
dc482cfa | 1007 | |
203b7e2e | 1008 | for ($i = 0; $i < $levels; $i++) { |
319770d7 | 1009 | $fillercell = new html_table_cell(); |
1010 | $fillercell->add_classes(array('fixedcolumn', 'cell', 'c0', 'topleft')); | |
1011 | $fillercell->text = ' '; | |
1012 | $fillercell->colspan = $colspan; | |
1013 | $fixedcolumntable->data[] = html_table_row::make(array($fillercell)); | |
203b7e2e | 1014 | } |
dc482cfa | 1015 | |
319770d7 | 1016 | $sortfirstname = html_link::make(clone($this->baseurl), $strfirstname); |
1017 | $sortfirstname->url->param('sortitemid', 'firstname'); | |
1018 | $sortlastname = html_link::make(clone($this->baseurl), $strlastname); | |
1019 | $sortlastname->url->param('sortitemid', 'lastname'); | |
1020 | ||
1021 | $headerrow = new html_table_row(); | |
1022 | $headerrow->add_class('heading'); | |
1023 | ||
1024 | $studentheader = new html_table_cell(); | |
1025 | $studentheader->add_classes(array('header', 'c0')); | |
1026 | $studentheader->scope = 'col'; | |
1027 | $studentheader->header = true; | |
1028 | $studentheader->id = 'studentheader'; | |
bb9b58a6 NC |
1029 | if (has_capability('gradereport/user:view', $this->context)) { |
1030 | $studentheader->colspan = 2; | |
1031 | } | |
319770d7 | 1032 | $studentheader->text = $OUTPUT->link($sortfirstname) . $firstarrow. '/ ' . $OUTPUT->link($sortlastname) . $lastarrow; |
1033 | ||
1034 | $headerrow->cells[] = $studentheader; | |
dc482cfa | 1035 | |
203b7e2e | 1036 | if ($showuseridnumber) { |
319770d7 | 1037 | $sortidnumberlink = html_link::make(clone($this->baseurl), get_string('idnumber')); |
1038 | $sortidnumberlink->url->param('sortitemid', 'idnumber'); | |
1039 | ||
1040 | $idnumberheader = new html_table_cell(); | |
1041 | $idnumberheader->add_classes(array('header', 'c0', 'useridnumber')); | |
1042 | $idnumberheader->scope = 'col'; | |
1043 | $idnumberheader->header = true; | |
1044 | $idnumberheader->text = $OUTPUT->link($sortidnumberlink); | |
1045 | ||
203b7e2e | 1046 | if ('idnumber' == $this->sortitemid) { |
1047 | if ($this->sortorder == 'ASC') { | |
319770d7 | 1048 | $idnumberheader->text .= print_arrow('up', $strsortasc, true); |
203b7e2e | 1049 | } else { |
319770d7 | 1050 | $idnumberheader->text .= print_arrow('down', $strsortdesc, true); |
203b7e2e | 1051 | } |
dc482cfa | 1052 | } |
319770d7 | 1053 | $headerrow->cells[] = $idnumberheader; |
dc482cfa | 1054 | } |
dc482cfa | 1055 | |
319770d7 | 1056 | $fixedcolumntable->data[] = $headerrow; |
dc482cfa | 1057 | |
203b7e2e | 1058 | if ($USER->gradeediting[$this->courseid]) { |
319770d7 | 1059 | $controlsrow = new html_table_row(); |
1060 | $controlsrow->add_class('controls'); | |
1061 | $controlscell = new html_table_cell(); | |
1062 | $controlscell->add_classes(array('header', 'c0', 'controls')); | |
1063 | $controlscell->colspan = $colspan; | |
1064 | $controlscell->text = $this->get_lang_string('controls','grades'); | |
1065 | ||
1066 | $controlsrow->cells[] = $controlscell; | |
1067 | $fixedcolumntable->data[] = $controlsrow; | |
203b7e2e | 1068 | } |
dc482cfa | 1069 | |
319770d7 | 1070 | $rowclasses = array('even', 'odd'); |
dc482cfa | 1071 | |
203b7e2e | 1072 | foreach ($this->users as $userid => $user) { |
319770d7 | 1073 | $userrow = new html_table_row(); |
1074 | $userrow->add_classes(array('r'.$this->rowcount++, $rowclasses[$this->rowcount % 2])); | |
1075 | ||
1076 | $usercell = new html_table_cell(); | |
1077 | $usercell->add_classes(array('c0', 'user')); | |
1078 | $usercell->header = true; | |
1079 | $usercell->scope = 'row'; | |
1080 | $usercell->add_action('click', 'yui_set_row'); | |
dc482cfa | 1081 | |
203b7e2e | 1082 | if ($showuserimage) { |
319770d7 | 1083 | $usercell->text = $OUTPUT->container($OUTPUT->user_picture(moodle_user_picture::make($user, $this->courseid)), 'userpic'); |
203b7e2e | 1084 | } |
dc482cfa | 1085 | |
319770d7 | 1086 | $usercell->text .= $OUTPUT->link(html_link::make(new moodle_url($CFG->wwwroot.'/user/view.php', array('id' => $user->id, 'course' => $this->course->id)), fullname($user))); |
bb9b58a6 | 1087 | |
319770d7 | 1088 | $userrow->cells[] = $usercell; |
203b7e2e | 1089 | |
bb9b58a6 NC |
1090 | if (has_capability('gradereport/user:view', $this->context)) { |
1091 | $userreportcell = new html_table_cell(); | |
1092 | $userreportcell->add_class('userreport'); | |
1093 | $userreportcell->header = true; | |
1094 | $a->user = fullname($user); | |
1095 | $strgradesforuser = get_string('gradesforuser', 'grades', $a); | |
1096 | $userreporticon = new moodle_action_icon(); | |
1097 | $userreporticon->link->url = new moodle_url($CFG->wwwroot.'/grade/report/user/index.php', array('userid' => $user->id, 'id' => $this->course->id)); | |
1098 | $userreporticon->image->add_class('iconsmall'); | |
1099 | $userreporticon->image->src = $OUTPUT->old_icon_url('t/grades'); | |
1100 | $userreporticon->image->alt = $strgradesforuser; | |
1101 | $userreportcell->text = $OUTPUT->action_icon($userreporticon); | |
1102 | $userrow->cells[] = $userreportcell; | |
1103 | } | |
1104 | ||
203b7e2e | 1105 | if ($showuseridnumber) { |
319770d7 | 1106 | $idnumbercell = new html_table_cell(); |
1107 | $idnumbercell->add_classes(array('header', 'c0', 'useridnumber')); | |
1108 | $idnumbercell->header = true; | |
1109 | $idnumbercell->scope = 'row'; | |
1110 | $idnumbercell->add_action('click', 'yui_set_row'); | |
1111 | $userrow->cells[] = $idnumbercell; | |
203b7e2e | 1112 | } |
319770d7 | 1113 | $fixedcolumntable->data[] = $userrow; |
dc482cfa | 1114 | } |
dc482cfa | 1115 | |
203b7e2e | 1116 | if ($this->get_pref('showranges')) { |
319770d7 | 1117 | $rangerow = new html_table_row(); |
1118 | $rangerow->add_classes(array('range', 'r'.$this->rowcount++)); | |
1119 | $rangecell = new html_table_cell(); | |
1120 | $rangecell->add_classes(array('header', 'c0', 'range')); | |
1121 | $rangecell->colspan = $colspan; | |
1122 | $rangecell->header = true; | |
1123 | $rangecell->scope = 'row'; | |
1124 | $rangecell->text = $this->get_lang_string('range','grades'); | |
1125 | $rangerow->cells[] = $rangecell; | |
1126 | $fixedcolumntable->data[] = $rangerow; | |
203b7e2e | 1127 | } |
dc482cfa | 1128 | |
203b7e2e | 1129 | // Averages heading |
dc482cfa | 1130 | |
319770d7 | 1131 | $straveragegroup = get_string('groupavg', 'grades'); |
203b7e2e | 1132 | $straverage = get_string('overallaverage', 'grades'); |
1133 | $showaverages = $this->get_pref('showaverages'); | |
319770d7 | 1134 | $showaveragesgroup = $this->currentgroup && $showaverages; |
1135 | ||
1136 | if ($showaveragesgroup) { | |
1137 | $groupavgrow = new html_table_row(); | |
1138 | $groupavgrow->add_classes(array('groupavg', 'r'.$this->rowcount++)); | |
1139 | $groupavgcell = new html_table_cell(); | |
1140 | $groupavgcell->add_classes(array('header', 'c0', 'range')); | |
1141 | $groupavgcell->colspan = $colspan; | |
1142 | $groupavgcell->header = true; | |
1143 | $groupavgcell->scope = 'row'; | |
1144 | $groupavgcell->text = $straveragegroup; | |
1145 | $groupavgrow->cells[] = $groupavgcell; | |
1146 | $fixedcolumntable->data[] = $groupavgrow; | |
203b7e2e | 1147 | } |
dc482cfa | 1148 | |
203b7e2e | 1149 | if ($showaverages) { |
319770d7 | 1150 | $avgrow = new html_table_row(); |
1151 | $avgrow->add_classes(array('avg', 'r'.$this->rowcount++)); | |
1152 | $avgcell = new html_table_cell(); | |
1153 | $avgcell->add_classes(array('header', 'c0', 'range')); | |
1154 | $avgcell->colspan = $colspan; | |
1155 | $avgcell->header = true; | |
1156 | $avgcell->scope = 'row'; | |
1157 | $avgcell->text = $straverage; | |
1158 | $avgrow->cells[] = $avgcell; | |
1159 | $fixedcolumntable->data[] = $avgrow; | |
203b7e2e | 1160 | } |
1161 | ||
319770d7 | 1162 | $studentshtml .= $OUTPUT->container($OUTPUT->table($fixedcolumntable), 'left_scroller'); |
1163 | $studentshtml .= ' | |
203b7e2e | 1164 | <div class="right_scroller"> |
1165 | <table id="user-grades" class=""> | |
1166 | <tbody class="righttest">'; | |
dc482cfa | 1167 | |
203b7e2e | 1168 | } else { |
1169 | $studentshtml .= '<table id="user-grades" class="gradestable flexible boxaligncenter generaltable"> | |
1170 | <tbody>'; | |
1171 | } | |
dc482cfa | 1172 | |
1173 | return $studentshtml; | |
1174 | } | |
1175 | ||
18a00359 | 1176 | /** |
1177 | * Closes all open elements | |
1178 | */ | |
1179 | public function get_endhtml() { | |
1180 | global $CFG, $USER; | |
1181 | ||
795b745a | 1182 | $fixedstudents = $this->is_fixed_students(); |
18a00359 | 1183 | |
1184 | if ($fixedstudents) { | |
1185 | return "</tbody></table></div>"; | |
1186 | } else { | |
1187 | return "</tbody></table>"; | |
1188 | } | |
1189 | } | |
1190 | ||
4ba9941c | 1191 | /** |
5b508a08 | 1192 | * Builds and return the HTML row of column totals. |
1193 | * @param bool $grouponly Whether to return only group averages or all averages. | |
4ba9941c | 1194 | * @return string HTML |
1195 | */ | |
d24832f9 | 1196 | public function get_avghtml($grouponly=false) { |
1197 | global $CFG, $USER, $DB; | |
4ba9941c | 1198 | |
57068674 | 1199 | if (!$this->canviewhidden) { |
1200 | // totals might be affected by hiding, if user can not see hidden grades the aggregations might be altered | |
1201 | // better not show them at all if user can not see all hideen grades | |
1202 | return; | |
1203 | } | |
1204 | ||
5b508a08 | 1205 | $averagesdisplaytype = $this->get_pref('averagesdisplaytype'); |
1206 | $averagesdecimalpoints = $this->get_pref('averagesdecimalpoints'); | |
098042ba | 1207 | $meanselection = $this->get_pref('meanselection'); |
1208 | $shownumberofgrades = $this->get_pref('shownumberofgrades'); | |
1209 | ||
5b508a08 | 1210 | $avghtml = ''; |
aae94377 | 1211 | $avgcssclass = 'avg'; |
3446013d | 1212 | |
5b508a08 | 1213 | if ($grouponly) { |
1214 | $straverage = get_string('groupavg', 'grades'); | |
35079f53 | 1215 | $showaverages = $this->currentgroup && $this->get_pref('showaverages'); |
5b508a08 | 1216 | $groupsql = $this->groupsql; |
1217 | $groupwheresql = $this->groupwheresql; | |
319770d7 | 1218 | $groupwheresqlparams = $this->groupwheresql_params; |
aae94377 | 1219 | $avgcssclass = 'groupavg'; |
3446013d | 1220 | } else { |
6308b91c | 1221 | $straverage = get_string('overallaverage', 'grades'); |
5b508a08 | 1222 | $showaverages = $this->get_pref('showaverages'); |
0dba6cb2 | 1223 | $groupsql = ""; |
1224 | $groupwheresql = ""; | |
319770d7 | 1225 | $groupwheresqlparams = array(); |
3446013d | 1226 | } |
1227 | ||
a5b8be62 | 1228 | if ($shownumberofgrades) { |
1229 | $straverage .= ' (' . get_string('submissions', 'grades') . ') '; | |
1230 | } | |
1231 | ||
f8ae1f86 | 1232 | $totalcount = $this->get_numusers($grouponly); |
04259694 | 1233 | |
319770d7 | 1234 | list($usql, $rolesparams) = $DB->get_in_or_equal(explode(',', $this->gradebookroles), SQL_PARAMS_NAMED, 'grbr0'); |
d24832f9 | 1235 | |
5b508a08 | 1236 | if ($showaverages) { |
319770d7 | 1237 | $params = array_merge(array('courseid'=>$this->courseid), $rolesparams, $groupwheresqlparams); |
04259694 | 1238 | |
828af11c | 1239 | // find sums of all grade items in course |
1240 | $SQL = "SELECT g.itemid, SUM(g.finalgrade) AS sum | |
d24832f9 | 1241 | FROM {grade_items} gi |
1242 | JOIN {grade_grades} g ON g.itemid = gi.id | |
1243 | JOIN {user} u ON u.id = g.userid | |
1244 | JOIN {role_assignments} ra ON ra.userid = u.id | |
828af11c | 1245 | $groupsql |
b50371da | 1246 | WHERE gi.courseid = :courseid |
d24832f9 | 1247 | AND ra.roleid $usql |
828af11c | 1248 | AND ra.contextid ".get_related_contexts_string($this->context)." |
1249 | AND g.finalgrade IS NOT NULL | |
883187d0 | 1250 | $groupwheresql |
883187d0 | 1251 | GROUP BY g.itemid"; |
319770d7 | 1252 | $sumarray = array(); |
d24832f9 | 1253 | if ($sums = $DB->get_records_sql($SQL, $params)) { |
ab3444d7 | 1254 | foreach ($sums as $itemid => $csum) { |
319770d7 | 1255 | $sumarray[$itemid] = $csum->sum; |
7b61efbe | 1256 | } |
4ba9941c | 1257 | } |
66ef0471 | 1258 | |
9d35e66e | 1259 | $columncount=0; |
dc482cfa | 1260 | $avghtml = '<tr class="' . $avgcssclass . ' r'.$this->rowcount++.'">'; |
6df5b04e | 1261 | |
883187d0 | 1262 | // MDL-10875 Empty grades must be evaluated as grademin, NOT always 0 |
1263 | // This query returns a count of ungraded grades (NULL finalgrade OR no matching record in grade_grades table) | |
319770d7 | 1264 | $params = array_merge(array('courseid'=>$this->courseid), $rolesparams, $groupwheresqlparams); |
883187d0 | 1265 | $SQL = "SELECT gi.id, COUNT(u.id) AS count |
d24832f9 | 1266 | FROM {grade_items} gi |
1267 | CROSS JOIN {user} u | |
1268 | JOIN {role_assignments} ra ON ra.userid = u.id | |
1269 | LEFT OUTER JOIN {grade_grades} g ON (g.itemid = gi.id AND g.userid = u.id AND g.finalgrade IS NOT NULL) | |
828af11c | 1270 | $groupsql |
b50371da | 1271 | WHERE gi.courseid = :courseid |
d24832f9 | 1272 | AND ra.roleid $usql |
828af11c | 1273 | AND ra.contextid ".get_related_contexts_string($this->context)." |
1274 | AND g.id IS NULL | |
1275 | $groupwheresql | |
883187d0 | 1276 | GROUP BY gi.id"; |
828af11c | 1277 | |
319770d7 | 1278 | $ungradedcounts = $DB->get_records_sql($SQL, $params); |
883187d0 | 1279 | |
795b745a | 1280 | $fixedstudents = $this->is_fixed_students(); |
653a8648 | 1281 | if (!$fixedstudents) { |
1282 | $colspan=''; | |
1283 | if ($this->get_pref('showuseridnumber')) { | |
1284 | $colspan = 'colspan="2" '; | |
1285 | } | |
adf541d9 | 1286 | $avghtml .= '<th class="header c0 range" '.$colspan.' scope="row">'.$straverage.'</th>'; |
653a8648 | 1287 | } |
1288 | ||
b89a70ce | 1289 | foreach ($this->gtree->items as $itemid=>$unused) { |
1290 | $item =& $this->gtree->items[$itemid]; | |
1291 | ||
67881aa8 | 1292 | if ($item->needsupdate) { |
1293 | $avghtml .= '<td class="cell c' . $columncount++.'"><span class="gradingerror">'.get_string('error').'</span></td>'; | |
1294 | continue; | |
1295 | } | |
1296 | ||
319770d7 | 1297 | if (!isset($sumarray[$item->id])) { |
1298 | $sumarray[$item->id] = 0; | |
33a34cd4 | 1299 | } |
883187d0 | 1300 | |
319770d7 | 1301 | if (empty($ungradedcounts[$itemid])) { |
1302 | $ungradedcount = 0; | |
828af11c | 1303 | } else { |
319770d7 | 1304 | $ungradedcount = $ungradedcounts[$itemid]->count; |
d1556c09 | 1305 | } |
33a34cd4 | 1306 | |
c2efb501 | 1307 | if ($meanselection == GRADE_REPORT_MEAN_GRADED) { |
319770d7 | 1308 | $meancount = $totalcount - $ungradedcount; |
33a34cd4 | 1309 | } else { // Bump up the sum by the number of ungraded items * grademin |
319770d7 | 1310 | $sumarray[$item->id] += $ungradedcount * $item->grademin; |
1311 | $meancount = $totalcount; | |
33a34cd4 | 1312 | } |
1313 | ||
31a6c06c | 1314 | $decimalpoints = $item->get_decimals(); |
41f22daa | 1315 | |
bb384a8e | 1316 | // Determine which display type to use for this average |
2cc773f5 | 1317 | if ($USER->gradeediting[$this->courseid]) { |
1796708d | 1318 | $displaytype = GRADE_DISPLAY_TYPE_REAL; |
d622930b | 1319 | |
e0724506 | 1320 | } else if ($averagesdisplaytype == GRADE_REPORT_PREFERENCE_INHERIT) { // no ==0 here, please resave the report and user preferences |
d622930b | 1321 | $displaytype = $item->get_displaytype(); |
1322 | ||
1323 | } else { | |
bb384a8e | 1324 | $displaytype = $averagesdisplaytype; |
1325 | } | |
1326 | ||
31a6c06c | 1327 | // Override grade_item setting if a display preference (not inherit) was set for the averages |
e0724506 | 1328 | if ($averagesdecimalpoints == GRADE_REPORT_PREFERENCE_INHERIT) { |
d622930b | 1329 | $decimalpoints = $item->get_decimals(); |
1330 | ||
1331 | } else { | |
5b508a08 | 1332 | $decimalpoints = $averagesdecimalpoints; |
1333 | } | |
1334 | ||
319770d7 | 1335 | if (!isset($sumarray[$item->id]) || $meancount == 0) { |
66ef0471 | 1336 | $avghtml .= '<td class="cell c' . $columncount++.'">-</td>'; |
4ba9941c | 1337 | } else { |
319770d7 | 1338 | $sum = $sumarray[$item->id]; |
1339 | $avgradeval = $sum/$meancount; | |
d622930b | 1340 | $gradehtml = grade_format_gradevalue($avgradeval, $item, true, $displaytype, $decimalpoints); |
bb384a8e | 1341 | |
098042ba | 1342 | $numberofgrades = ''; |
098042ba | 1343 | if ($shownumberofgrades) { |
319770d7 | 1344 | $numberofgrades = " ($meancount)"; |
098042ba | 1345 | } |
1346 | ||
1347 | $avghtml .= '<td class="cell c' . $columncount++.'">'.$gradehtml.$numberofgrades.'</td>'; | |
4ba9941c | 1348 | } |
1349 | } | |
5b508a08 | 1350 | $avghtml .= '</tr>'; |
4ba9941c | 1351 | } |
5b508a08 | 1352 | return $avghtml; |
4ba9941c | 1353 | } |
1354 | ||
e5161d0c | 1355 | /** |
2f61fc0e | 1356 | * Builds and return the HTML row of ranges for each column (i.e. range). |
e5161d0c | 1357 | * @return string HTML |
1358 | */ | |
d24832f9 | 1359 | public function get_rangehtml() { |
653a8648 | 1360 | global $CFG, $USER; |
2f61fc0e | 1361 | |
653a8648 | 1362 | $rangehtml = ''; |
61649211 | 1363 | if ($this->get_pref('showranges')) { |
d622930b | 1364 | $rangesdisplaytype = $this->get_pref('rangesdisplaytype'); |
5b508a08 | 1365 | $rangesdecimalpoints = $this->get_pref('rangesdecimalpoints'); |
d622930b | 1366 | |
9d35e66e | 1367 | $columncount=0; |
653a8648 | 1368 | $rangehtml = '<tr class="range r'.$this->rowcount++.' heading">'; |
9d35e66e | 1369 | |
795b745a | 1370 | $fixedstudents = $this->is_fixed_students(); |
653a8648 | 1371 | if (!$fixedstudents) { |
1372 | $colspan=''; | |
1373 | if ($this->get_pref('showuseridnumber')) { | |
1374 | $colspan = 'colspan="2" '; | |
1375 | } | |
adf541d9 | 1376 | $rangehtml .= '<th class="header c0 range" '.$colspan.' scope="row">'.$this->get_lang_string('range','grades').'</th>'; |
653a8648 | 1377 | } |
9d35e66e | 1378 | |
dc482cfa | 1379 | foreach ($this->gtree->items as $itemid=>$unused) { |
1380 | $item =& $this->gtree->items[$itemid]; | |
5b508a08 | 1381 | |
66ef0471 | 1382 | |
80fb1cf9 | 1383 | $hidden = ''; |
1384 | if ($item->is_hidden()) { | |
1385 | $hidden = ' hidden '; | |
1386 | } | |
1387 | ||
319770d7 | 1388 | $formattedrange = $item->get_formatted_range($rangesdisplaytype, $rangesdecimalpoints); |
4dc81cc7 | 1389 | |
319770d7 | 1390 | $rangehtml .= '<th class="header c'.$columncount++.' range"><span class="rangevalues'.$hidden.'">'. $formattedrange .'</span></th>'; |
dc482cfa | 1391 | |
4ba9941c | 1392 | } |
653a8648 | 1393 | $rangehtml .= '</tr>'; |
4ba9941c | 1394 | } |
653a8648 | 1395 | return $rangehtml; |
4ba9941c | 1396 | } |
d24832f9 | 1397 | |
9ecd4386 | 1398 | /** |
1399 | * Builds and return the HTML row of ranges for each column (i.e. range). | |
1400 | * @return string HTML | |
1401 | */ | |
d24832f9 | 1402 | public function get_iconshtml() { |
d0d1293d | 1403 | global $USER, $CFG; |
9ecd4386 | 1404 | |
1405 | $iconshtml = ''; | |
322a5f63 | 1406 | if ($USER->gradeediting[$this->courseid]) { |
1407 | ||
dc482cfa | 1408 | $iconshtml = '<tr class="controls">'; |
9ecd4386 | 1409 | |
795b745a | 1410 | $fixedstudents = $this->is_fixed_students(); |
d0d1293d | 1411 | $showuseridnumber = $this->get_pref('showuseridnumber'); |
1412 | ||
1413 | $colspan = ''; | |
1414 | if ($showuseridnumber) { | |
1415 | $colspan = 'colspan="2"'; | |
1416 | } | |
1417 | ||
1418 | if (!$fixedstudents) { | |
1419 | $iconshtml .= '<th class="header c0 controls" scope="row" '.$colspan.'>'.$this->get_lang_string('controls','grades').'</th>'; | |
1420 | } | |
1421 | ||
dc482cfa | 1422 | $columncount = 0; |
1423 | foreach ($this->gtree->items as $itemid=>$unused) { | |
9ecd4386 | 1424 | // emulate grade element |
d24832f9 | 1425 | $item =& $this->gtree->get_item($itemid); |
1426 | ||
9ecd4386 | 1427 | $eid = $this->gtree->get_item_eid($item); |
1428 | $element = $this->gtree->locate_element($eid); | |
1429 | ||
dc482cfa | 1430 | $iconshtml .= '<td class="controls cell c'.$columncount++.' icons">' . $this->get_icons($element) . '</td>'; |
9ecd4386 | 1431 | } |
1432 | $iconshtml .= '</tr>'; | |
1433 | } | |
1434 | return $iconshtml; | |
1435 | } | |
4ba9941c | 1436 | |
1437 | /** | |
1438 | * Given a grade_category, grade_item or grade_grade, this function | |
1439 | * figures out the state of the object and builds then returns a div | |
1440 | * with the icons needed for the grader report. | |
1441 | * | |
1442 | * @param object $object | |
4ba9941c | 1443 | * @return string HTML |
1444 | */ | |
d24832f9 | 1445 | protected function get_icons($element) { |
319770d7 | 1446 | global $CFG, $USER, $OUTPUT; |
4ba9941c | 1447 | |
2cc773f5 | 1448 | if (!$USER->gradeediting[$this->courseid]) { |
1449 | return '<div class="grade_icons" />'; | |
79eabc2a | 1450 | } |
4ba9941c | 1451 | |
2cc773f5 | 1452 | // Init all icons |
319770d7 | 1453 | $editicon = ''; |
dc482cfa | 1454 | |
1455 | if ($element['type'] != 'categoryitem' && $element['type'] != 'courseitem') { | |
319770d7 | 1456 | $editicon = $this->gtree->get_edit_icon($element, $this->gpr); |
dc482cfa | 1457 | } |
1458 | ||
319770d7 | 1459 | $editcalculationicon = ''; |
1460 | $showhideicon = ''; | |
1461 | $lockunlockicon = ''; | |
4ba9941c | 1462 | |
a5b8be62 | 1463 | if (has_capability('moodle/grade:manage', $this->context)) { |
4ba9941c | 1464 | |
a5b8be62 | 1465 | if ($this->get_pref('showcalculations')) { |
319770d7 | 1466 | $editcalculationicon = $this->gtree->get_calculation_icon($element, $this->gpr); |
a5b8be62 | 1467 | } |
1468 | ||
1469 | if ($this->get_pref('showeyecons')) { | |
319770d7 | 1470 | $showhideicon = $this->gtree->get_hiding_icon($element, $this->gpr); |
a5b8be62 | 1471 | } |
4ba9941c | 1472 | |
a5b8be62 | 1473 | if ($this->get_pref('showlocks')) { |
319770d7 | 1474 | $lockunlockicon = $this->gtree->get_locking_icon($element, $this->gpr); |
a5b8be62 | 1475 | } |
4ba9941c | 1476 | } |
1477 | ||
319770d7 | 1478 | return $OUTPUT->container($editicon.$editcalculationicon.$showhideicon.$lockunlockicon, 'grade_icons'); |
4faf5f99 | 1479 | } |
1480 | ||
1481 | /** | |
1482 | * Given a category element returns collapsing +/- icon if available | |
1483 | * @param object $object | |
1484 | * @return string HTML | |
1485 | */ | |
d24832f9 | 1486 | protected function get_collapsing_icon($element) { |
5d3b9994 | 1487 | global $OUTPUT; |
4faf5f99 | 1488 | |
319770d7 | 1489 | $icon = ''; |
2cc773f5 | 1490 | // If object is a category, display expand/contract icon |
384960dd | 1491 | if ($element['type'] == 'category') { |
2cc773f5 | 1492 | // Load language strings |
319770d7 | 1493 | $strswitchminus = $this->get_lang_string('aggregatesonly', 'grades'); |
1494 | $strswitchplus = $this->get_lang_string('gradesonly', 'grades'); | |
1495 | $strswitchwhole = $this->get_lang_string('fullmode', 'grades'); | |
384960dd | 1496 | |
319770d7 | 1497 | $contractexpandicon = new moodle_action_icon(); |
1498 | $contractexpandicon->link->url = new moodle_url($this->gpr->get_return_url(null, array('target'=>$element['eid'], 'action'=>'switch_minus', 'sesskey'=>sesskey()))); | |
1499 | $contractexpandicon->image->add_class('iconsmall'); | |
1500 | $contractexpandicon->image->src = $OUTPUT->old_icon_url('t/switch_minus'); | |
1501 | $contractexpandicon->image->alt = $strswitchminus; | |
48b5d8f3 | 1502 | |
384960dd | 1503 | if (in_array($element['object']->id, $this->collapsed['aggregatesonly'])) { |
319770d7 | 1504 | $contractexpandicon->image->src = $OUTPUT->old_icon_url('t/switch_plus'); |
1505 | $contractexpandicon->image->alt = $strswitchplus; | |
1506 | $contractexpandicon->link->url->param('action', 'switch_plus'); | |
384960dd | 1507 | } elseif (in_array($element['object']->id, $this->collapsed['gradesonly'])) { |
319770d7 | 1508 | $contractexpandicon->image->src = $OUTPUT->old_icon_url('t/switch_whole'); |
1509 | $contractexpandicon->image->alt = $strswitchwhole; | |
1510 | $contractexpandicon->link->url->param('action', 'switch_whole'); | |
2cc773f5 | 1511 | } |
319770d7 | 1512 | $icon = $OUTPUT->action_icon($contractexpandicon); |
4ba9941c | 1513 | } |
319770d7 | 1514 | return $icon; |
4ba9941c | 1515 | } |
48b5d8f3 | 1516 | |
1517 | /** | |
1518 | * Processes a single action against a category, grade_item or grade. | |
1519 | * @param string $target eid ({type}{id}, e.g. c4 for category4) | |
1520 | * @param string $action Which action to take (edit, delete etc...) | |
1521 | * @return | |
1522 | */ | |
d24832f9 | 1523 | public function process_action($target, $action) { |
4faf5f99 | 1524 | // TODO: this code should be in some grade_tree static method |
48b5d8f3 | 1525 | $targettype = substr($target, 0, 1); |
1526 | $targetid = substr($target, 1); | |
4faf5f99 | 1527 | // TODO: end |
1528 | ||
1529 | if ($collapsed = get_user_preferences('grade_report_grader_collapsed_categories')) { | |
1530 | $collapsed = unserialize($collapsed); | |
1531 | } else { | |
384960dd | 1532 | $collapsed = array('aggregatesonly' => array(), 'gradesonly' => array()); |
4faf5f99 | 1533 | } |
1534 | ||
48b5d8f3 | 1535 | switch ($action) { |
384960dd | 1536 | case 'switch_minus': // Add category to array of aggregatesonly |
1537 | if (!in_array($targetid, $collapsed['aggregatesonly'])) { | |
1538 | $collapsed['aggregatesonly'][] = $targetid; | |
4faf5f99 | 1539 | set_user_preference('grade_report_grader_collapsed_categories', serialize($collapsed)); |
1540 | } | |
48b5d8f3 | 1541 | break; |
4faf5f99 | 1542 | |
384960dd | 1543 | case 'switch_plus': // Remove category from array of aggregatesonly, and add it to array of gradesonly |
1544 | $key = array_search($targetid, $collapsed['aggregatesonly']); | |
4faf5f99 | 1545 | if ($key !== false) { |
384960dd | 1546 | unset($collapsed['aggregatesonly'][$key]); |
4faf5f99 | 1547 | } |
384960dd | 1548 | if (!in_array($targetid, $collapsed['gradesonly'])) { |
1549 | $collapsed['gradesonly'][] = $targetid; | |
1550 | } | |
1551 | set_user_preference('grade_report_grader_collapsed_categories', serialize($collapsed)); | |
48b5d8f3 | 1552 | break; |
384960dd | 1553 | case 'switch_whole': // Remove the category from the array of collapsed cats |
1554 | $key = array_search($targetid, $collapsed['gradesonly']); | |
1555 | if ($key !== false) { | |
1556 | unset($collapsed['gradesonly'][$key]); | |
1557 | set_user_preference('grade_report_grader_collapsed_categories', serialize($collapsed)); | |
1558 | } | |
4faf5f99 | 1559 | |
384960dd | 1560 | break; |
48b5d8f3 | 1561 | default: |
1562 | break; | |
1563 | } | |
1564 | ||
1565 | return true; | |
1566 | } | |
03fcc729 | 1567 | |
795b745a | 1568 | /** |
1569 | * Returns whether or not to display fixed students column. | |
1570 | * Includes a browser check, because IE6 doesn't support the scrollbar. | |
1571 | * | |
1572 | * @return bool | |
1573 | */ | |
1574 | public function is_fixed_students() { | |
1575 | global $USER, $CFG; | |
03fcc729 | 1576 | return empty($USER->screenreader) && $CFG->grade_report_fixedstudents && |
1577 | (check_browser_version('MSIE', '7.0') || | |
795b745a | 1578 | check_browser_version('Firefox', '2.0') || |
1579 | check_browser_version('Gecko', '2006010100') || | |
1580 | check_browser_version('Camino', '1.0') || | |
1581 | check_browser_version('Opera', '6.0') || | |
03fcc729 | 1582 | check_browser_version('Safari', '2.0')); |
795b745a | 1583 | } |
4ba9941c | 1584 | } |
1585 | ?> |