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