MDL-20204 fixed html-writer::tag() parameter order to match the rest of the api
[moodle.git] / mod / workshop / renderer.php
1 <?php
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/>.
18 /**
19  * All workshop module renderers are defined here
20  *
21  * @package   mod-workshop
22  * @copyright 2009 David Mudrak <david.mudrak@gmail.com>
23  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 defined('MOODLE_INTERNAL') || die();
28 /**
29  * Workshop module renderer class
30  *
31  * @copyright 2009 David Mudrak <david.mudrak@gmail.com>
32  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
33  */
34 class mod_workshop_renderer extends plugin_renderer_base {
36     /**
37      * Returns html code for a status message
38      *
39      * This should be replaced by a core system of displaying messages, as for example Mahara has.
40      *
41      * @param string $message to display
42      * @return string html
43      */
44     public function status_message(stdclass $message) {
45         if (empty($message->text)) {
46             return '';
47         }
48         $sty = empty($message->sty) ? 'info' : $message->sty;
50         $o = html_writer::tag('span', $message->text);
51         $closer = html_writer::tag('a', array('href' => $this->page->url->out()),
52                     get_string('messageclose', 'workshop'));
53         $o .= $this->output->container($closer, 'status-message-closer');
54         if (isset($message->extra)) {
55             $o .= $message->extra;
56         }
57         return $this->output->container($o, array('status-message', $sty));
58     }
60     /**
61      * Wraps html code returned by the allocator init() method
62      *
63      * Supplied argument can be either integer status code or an array of string messages. Messages
64      * in a array can have optional prefix or prefixes, using '::' as delimiter. Prefixes determine
65      * the type of the message and may influence its visualisation.
66      *
67      * @param mixed $result int|array returned by init()
68      * @return string html to be echoed
69      */
70     public function allocation_init_result($result='') {
71         $msg = new stdclass();
72         if ($result === workshop::ALLOCATION_ERROR) {
73             $msg = (object)array('text' => get_string('allocationerror', 'workshop'), 'sty' => 'error');
74         } else {
75             $msg = (object)array('text' => get_string('allocationdone', 'workshop'), 'sty' => 'ok');
76         }
77         $o = $this->status_message($msg);
78         if (is_array($result)) {
79             $o .= html_writer::start_tag('ul', array('class' => 'allocation-init-results'));
80             foreach ($result as $message) {
81                 $parts  = explode('::', $message);
82                 $text   = array_pop($parts);
83                 $class  = implode(' ', $parts);
84                 if (in_array('debug', $parts) && !debugging('', DEBUG_DEVELOPER)) {
85                     // do not display allocation debugging messages
86                     continue;
87                 }
88                 $o .= html_writer::tag('li', $text, array('class' => $class)) . "\n";
89             }
90             $o .= html_writer::end_tag('ul');
91             $o .= $this->output->continue_button($this->page->url->out());
92         }
93         return $o;
94     }
96     /**
97      * Display a short summary of the submission
98      *
99      * The passed submission object must define at least: id, title, timecreated, timemodified,
100      * authorid, authorfirstname, authorlastname, authorpicture and authorimagealt
101      *
102      * @param stdclass $submission     The submission record
103      * @param bool     $showauthorname Should the author name be displayed
104      * @return string html to be echoed
105      */
106     public function submission_summary(stdclass $submission, $showauthorname=false) {
107         global $CFG;
109         $o  = '';    // output HTML code
110         $classes = 'submission-summary';
111         if (!$showauthorname) {
112             $classes .= ' anonymous';
113         }
114         $o .= $this->output->container_start($classes);  // main wrapper
115         $url = new moodle_url('/mod/workshop/submission.php',
116                               array('cmid' => $this->page->context->instanceid, 'id' => $submission->id));
117         $o .= html_writer::link($url, format_string($submission->title), array('class'=>'title'));
118         if ($showauthorname) {
119             $author             = new stdclass();
120             $author->id         = $submission->authorid;
121             $author->firstname  = $submission->authorfirstname;
122             $author->lastname   = $submission->authorlastname;
123             $author->picture    = $submission->authorpicture;
124             $author->imagealt   = $submission->authorimagealt;
125             $userpic            = $this->output->user_picture($author, array('courseid' => $this->page->course->id, 'size' => 35));
126             $userurl            = new moodle_url('/user/view.php',
127                                             array('id' => $author->id, 'course' => $this->page->course->id));
128             $a                  = new stdclass();
129             $a->name            = fullname($author);
130             $a->url             = $userurl->out();
131             $byfullname         = get_string('byfullname', 'workshop', $a);
133             $oo  = $this->output->container($userpic, 'picture');
134             $oo .= $this->output->container($byfullname, 'fullname');
135             $o .= $this->output->container($oo, 'author');
136         }
137         $created = get_string('userdatecreated', 'workshop', userdate($submission->timecreated));
138         $o .= $this->output->container($created, 'userdate created');
139         if ($submission->timemodified > $submission->timecreated) {
140             $modified = get_string('userdatemodified', 'workshop', userdate($submission->timemodified));
141             $o .= $this->output->container($modified, 'userdate modified');
142         }
143         $o .= $this->output->container_end(); // end of the main wrapper
145         return $o;
146     }
148     /**
149      * Displays the submission fulltext
150      *
151      * By default, this looks similar to a forum post.
152      *
153      * @param stdclass $submission     The submission data
154      * @param bool     $showauthorname Should the author name be displayed
155      * @return string html to be echoed
156      */
157     public function submission_full(stdclass $submission, $showauthorname=false) {
158         global $CFG;
160         $o  = '';    // output HTML code
161         $classes = 'submission-full';
162         if (!$showauthorname) {
163             $classes .= ' anonymous';
164         }
165         $o .= $this->output->container_start($classes);
166         $o .= $this->output->container_start('header');
167         $o .= $this->output->heading(format_string($submission->title), 3, 'title');
168         if ($showauthorname) {
169             $author             = new stdclass();
170             $author->id         = $submission->authorid;
171             $author->firstname  = $submission->authorfirstname;
172             $author->lastname   = $submission->authorlastname;
173             $author->picture    = $submission->authorpicture;
174             $author->imagealt   = $submission->authorimagealt;
175             $userpic            = $this->output->user_picture($author, array('courseid' => $this->page->course->id, 'size' => 64));
176             $userurl            = new moodle_url('/user/view.php',
177                                             array('id' => $author->id, 'course' => $this->page->course->id));
178             $a                  = new stdclass();
179             $a->name            = fullname($author);
180             $a->url             = $userurl->out();
181             $byfullname         = get_string('byfullname', 'workshop', $a);
182             $oo  = $this->output->container($userpic, 'picture');
183             $oo .= $this->output->container($byfullname, 'fullname');
185             $o .= $this->output->container($oo, 'author');
186         }
187         $created = get_string('userdatecreated', 'workshop', userdate($submission->timecreated));
188         $o .= $this->output->container($created, 'userdate created');
189         if ($submission->timemodified > $submission->timecreated) {
190             $modified = get_string('userdatemodified', 'workshop', userdate($submission->timemodified));
191             $o .= $this->output->container($modified, 'userdate modified');
192         }
193         $o .= $this->output->container_end(); // end of header
195         $content = format_text($submission->content, $submission->contentformat);
196         $content = file_rewrite_pluginfile_urls($content, 'pluginfile.php', $this->page->context->id,
197                                                         'workshop_submission_content', $submission->id);
198         $o .= $this->output->container($content, 'content');
200         $o .= $this->submission_attachments($submission);
202         $o .= $this->output->container_end(); // end of submission-full
204         return $o;
205     }
207     /**
208      * Renders a list of files attached to the submission
209      *
210      * If format==html, then format a html string. If format==text, then format a text-only string.
211      * Otherwise, returns html for non-images and html to display the image inline.
212      *
213      * @param stdclass $submission Submission record
214      * @param string format        The format of the returned string
215      * @return string              HTML code to be echoed
216      */
217     public function submission_attachments(stdclass $submission, $format=null) {
218         global $CFG;
219         require_once($CFG->libdir.'/filelib.php');
221         $fs     = get_file_storage();
222         $ctx    = $this->page->context;
223         $files  = $fs->get_area_files($ctx->id, 'workshop_submission_attachment', $submission->id);
225         $outputimgs     = "";   // images to be displayed inline
226         $outputfiles    = "";   // list of attachment files
228         foreach ($files as $file) {
229             if ($file->is_directory()) {
230                 continue;
231             }
233             $filepath   = $file->get_filepath();
234             $filename   = $file->get_filename();
235             $fileurl    = file_encode_url($CFG->wwwroot . '/pluginfile.php',
236                                 '/' . $ctx->id . '/workshop_submission_attachment/' . $submission->id . $filepath . $filename, true);
237             $type       = $file->get_mimetype();
238             $type       = mimeinfo_from_type("type", $type);
239             $image      = html_writer::empty_tag('img', array('src'=>$this->output->pix_url(file_mimetype_icon($type)), 'alt'=>$type, 'class'=>'icon'));
241             $linkhtml   = html_writer::link($fileurl, $image) . html_writer::link($fileurl, $filename);
242             $linktxt    = "$filename [$fileurl]";
244             if ($format == "html") {
245                 // this is the same as the code in the last else-branch
246                 $outputfiles .= html_writer::tag('li', $linkhtml, array('class' => $type));
248             } else if ($format == "text") {
249                 $outputfiles .= $linktxt . "\n";
251             } else {
252                 if (in_array($type, array('image/gif', 'image/jpeg', 'image/png'))) {
253                     $preview     = html_writer::empty_tag('img', array('src'=>$fileurl, 'alt'=>'', 'class'=>'preview'));
254                     $preview     = html_writer::tag('a', $preview, array('href'=>$fileurl));
255                     $outputimgs .= $this->output->container($preview);
256                 } else {
257                     // this is the same as the code in html if-branch
258                     $outputfiles .= html_writer::tag('li', $linkhtml, array('class' => $type));
259                 }
260             }
261         }
263         if ($outputimgs) {
264             $outputimgs = $this->output->container($outputimgs, 'images');
265         }
266         if ($format !== "text") {
267             $outputfiles = html_writer::tag('ul', $outputfiles, array('class' => 'files'));
268         }
269         return $this->output->container($outputimgs . $outputfiles, 'attachments');
270     }
272     /**
273      * Display a short summary of the example submission
274      *
275      * The passed submission object must define at least: id and title
276      *
277      * @param stdclass $data prepared by workshop::prepare_example_summary()
278      * @return string html to be echoed
279      */
280     public function example_summary(stdclass $summary) {
281         global $CFG;
283         $o  = '';    // output HTML code
285         // wrapping box
286         $o .= $this->output->box_start('generalbox example-summary ' . $summary->status);
288         // title
289         $o .= $this->output->container_start('example-title');
290         $url = new moodle_url('/mod/workshop/exsubmission.php',
291                               array('cmid' => $this->page->context->instanceid, 'id' => $summary->example->id));
292         $o .= html_writer::link($url, format_string($summary->example->title), array('class'=>'title'));
294         // dirty hack to guess if the current user is example manager or not
295         if ($summary->example->weight == 1) {
296             $url = new moodle_url('/mod/workshop/exsubmission.php',
297                                         array('cmid' => $this->page->context->instanceid, 'id' => $summary->example->id, 'edit' => 'on'));
298             $o .= $this->output->action_icon($url, new pix_icon('i/edit', get_string('edit')));
299         }
300         $o .= $this->output->container_end();
302         // additional info
303         if ($summary->status == 'notgraded') {
304             $o .= $this->output->container(get_string('nogradeyet', 'workshop'), 'example-info nograde');
305         } else {
306             $o .= $this->output->container(get_string('examplegrade', 'workshop' , $summary->gradeinfo), 'example-info grade');
307         }
309         // button to assess
310         $o .= $this->output->container($this->output->render($summary->btnform), 'example-actions');
312         // end of wrapping box
313         $o .= $this->output->box_end();
315         return $o;
316     }
318     /**
319      * Displays the example submission fulltext
320      *
321      * By default, this looks similar to a forum post.
322      *
323      * @param stdclass $example        The example submission data
324      * @return string html to be echoed
325      */
326     public function example_full(stdclass $example) {
327         global $CFG;
329         $o  = '';    // output HTML code
330         $classes = 'submission-full example';
331         $o .= $this->output->container_start($classes);
332         $o .= $this->output->container_start('header');
333         $o .= $this->output->heading(format_string($example->title), 3, 'title');
334         $created = get_string('userdatecreated', 'workshop', userdate($example->timecreated));
335         $o .= $this->output->container($created, 'userdate created');
336         if ($example->timemodified > $example->timecreated) {
337             $modified = get_string('userdatemodified', 'workshop', userdate($example->timemodified));
338             $o .= $this->output->container($modified, 'userdate modified');
339         }
340         $o .= $this->output->container_end(); // end of header
342         $content = format_text($example->content, $example->contentformat);
343         $content = file_rewrite_pluginfile_urls($content, 'pluginfile.php', $this->page->context->id,
344                                                         'workshop_submission_content', $example->id);
345         $o .= $this->output->container($content, 'content');
347         $o .= $this->submission_attachments($example);
349         $o .= $this->output->container_end(); // end of example-full
351         return $o;
352     }
354     /**
355      * Renders the user plannner tool
356      *
357      * @param array $plan as returned by {@link workshop::prepare_user_plan()}
358      * @return string html code to be displayed
359      */
360     public function user_plan(array $plan) {
361         if (empty($plan)) {
362             throw new coding_exception('you must provide the prepared user plan to be rendered');
363         }
364         $table = new html_table();
365         $table->set_classes('userplan');
366         $table->head = array();
367         $table->colclasses = array();
368         $row = new html_table_row();
369         $row->set_classes('phasetasks');
370         foreach ($plan as $phasecode => $phase) {
371             $title = html_writer::tag('span', $phase->title);
372             $actions = '';
373             foreach ($phase->actions as $action) {
374                 switch ($action->type) {
375                 case 'switchphase':
376                     $actions .= $this->output->action_icon($action->url, new pix_icon('i/marker', get_string('switchphase', 'workshop')));
377                     break;
378                 }
379             }
380             if (!empty($actions)) {
381                 $actions = $this->output->container($actions, 'actions');
382             }
383             $table->head[] = $this->output->container($title . $actions);
384             $classes = 'phase' . $phasecode;
385             if ($phase->active) {
386                 $classes .= ' active';
387             } else {
388                 $classes .= ' nonactive';
389             }
390             $table->colclasses[] = $classes;
391             $cell = new html_table_cell();
392             $cell->text = $this->user_plan_tasks($phase->tasks);
393             $row->cells[] = $cell;
394         }
395         $table->data = array($row);
397         return $this->output->table($table);
398     }
400     /**
401      * Renders the tasks for the single phase in the user plan
402      *
403      * @param stdclass $tasks
404      * @return string html code
405      */
406     protected function user_plan_tasks(array $tasks) {
407         $out = '';
408         foreach ($tasks as $taskcode => $task) {
409             $classes = '';
410             $icon = null;
411             if ($task->completed === true) {
412                 $classes .= ' completed';
413             } elseif ($task->completed === false) {
414                 $classes .= ' fail';
415             } elseif ($task->completed === 'info') {
416                 $classes .= ' info';
417             }
418             if (is_null($task->link)) {
419                 $title = $task->title;
420             } else {
421                 $title = html_writer::link($task->link, $task->title);
422             }
423             $title = $this->output->container($title, 'title');
424             $details = $this->output->container($task->details, 'details');
425             $out .= html_writer::tag('li', $title . $details, array('class' => $classes));
426         }
427         if ($out) {
428             $out = html_writer::tag('ul', $out, array('class' => 'tasks'));
429         }
430         return $out;
431     }
433     /**
434      * Renders the workshop grading report
435      *
436      * Grades must be already rounded to the set number of decimals or must be null (in which later case,
437      * the [[nullgrade]] string shall be displayed).
438      *
439      * @param stdclass $data prepared by {@link workshop::prepare_grading_report()}
440      * @param stdclass $options display options object with properties ->showauthornames ->showreviewernames ->sortby ->sorthow
441      *          ->showsubmissiongrade ->showgradinggrade
442      * @return string html code
443      */
444     public function grading_report(stdclass $data, stdclass $options) {
445         $grades             = $data->grades;
446         $userinfo           = $data->userinfo;
448         if (empty($grades)) {
449             return '';
450         }
452         $table = new html_table();
453         $table->set_classes('grading-report');
455         $sortbyfirstname = $this->sortable_heading(get_string('firstname'), 'firstname', $options->sortby, $options->sorthow);
456         $sortbylastname = $this->sortable_heading(get_string('lastname'), 'lastname', $options->sortby, $options->sorthow);
457         if (self::fullname_format() == 'lf') {
458             $sortbyname = $sortbylastname . ' / ' . $sortbyfirstname;
459         } else {
460             $sortbyname = $sortbyfirstname . ' / ' . $sortbylastname;
461         }
463         $table->head = array();
464         $table->head[] = $sortbyname;
465         $table->head[] = $this->sortable_heading(get_string('submission', 'workshop'), 'submissiontitle',
466                 $options->sortby, $options->sorthow);
467         $table->head[] = $this->sortable_heading(get_string('receivedgrades', 'workshop'));
468         if ($options->showsubmissiongrade) {
469             $table->head[] = $this->sortable_heading(get_string('submissiongradeof', 'workshop', $data->maxgrade),
470                     'submissiongrade', $options->sortby, $options->sorthow);
471         }
472         $table->head[] = $this->sortable_heading(get_string('givengrades', 'workshop'));
473         if ($options->showgradinggrade) {
474             $table->head[] = $this->sortable_heading(get_string('gradinggradeof', 'workshop', $data->maxgradinggrade),
475                     'gradinggrade', $options->sortby, $options->sorthow);
476         }
478         $table->rowclasses  = array();
479         $table->colclasses  = array();
480         $table->data        = array();
482         foreach ($grades as $participant) {
483             $numofreceived  = count($participant->reviewedby);
484             $numofgiven     = count($participant->reviewerof);
486             // compute the number of <tr> table rows needed to display this participant
487             if ($numofreceived > 0 and $numofgiven > 0) {
488                 $numoftrs       = workshop::lcm($numofreceived, $numofgiven);
489                 $spanreceived   = $numoftrs / $numofreceived;
490                 $spangiven      = $numoftrs / $numofgiven;
491             } elseif ($numofreceived == 0 and $numofgiven > 0) {
492                 $numoftrs       = $numofgiven;
493                 $spanreceived   = $numoftrs;
494                 $spangiven      = $numoftrs / $numofgiven;
495             } elseif ($numofreceived > 0 and $numofgiven == 0) {
496                 $numoftrs       = $numofreceived;
497                 $spanreceived   = $numoftrs / $numofreceived;
498                 $spangiven      = $numoftrs;
499             } else {
500                 $numoftrs       = 1;
501                 $spanreceived   = 1;
502                 $spangiven      = 1;
503             }
505             for ($tr = 0; $tr < $numoftrs; $tr++) {
506                 $row = new html_table_row();
507                 // column #1 - participant - spans over all rows
508                 if ($tr == 0) {
509                     $cell = new html_table_cell();
510                     $cell->text = $this->grading_report_participant($participant, $userinfo);
511                     $cell->rowspan = $numoftrs;
512                     $cell->add_class('participant');
513                     $row->cells[] = $cell;
514                 }
515                 // column #2 - submission - spans over all rows
516                 if ($tr == 0) {
517                     $cell = new html_table_cell();
518                     $cell->text = $this->grading_report_submission($participant);
519                     $cell->rowspan = $numoftrs;
520                     $cell->add_class('submission');
521                     $row->cells[] = $cell;
522                 }
523                 // column #3 - received grades
524                 if ($tr % $spanreceived == 0) {
525                     $idx = intval($tr / $spanreceived);
526                     $assessment = self::array_nth($participant->reviewedby, $idx);
527                     $cell = new html_table_cell();
528                     $cell->text = $this->grading_report_assessment($assessment, $options->showreviewernames, $userinfo,
529                             get_string('gradereceivedfrom', 'workshop'));
530                     $cell->rowspan = $spanreceived;
531                     $cell->add_class('receivedgrade');
532                     if (is_null($assessment) or is_null($assessment->grade)) {
533                         $cell->add_class('null');
534                     } else {
535                         $cell->add_class('notnull');
536                     }
537                     $row->cells[] = $cell;
538                 }
539                 // column #4 - total grade for submission
540                 if ($options->showsubmissiongrade and $tr == 0) {
541                     $cell = new html_table_cell();
542                     $cell->text = $this->grading_report_grade($participant->submissiongrade, $participant->submissiongradeover);
543                     $cell->rowspan = $numoftrs;
544                     $cell->add_class('submissiongrade');
545                     $row->cells[] = $cell;
546                 }
547                 // column #5 - given grades
548                 if ($tr % $spangiven == 0) {
549                     $idx = intval($tr / $spangiven);
550                     $assessment = self::array_nth($participant->reviewerof, $idx);
551                     $cell = new html_table_cell();
552                     $cell->text = $this->grading_report_assessment($assessment, $options->showauthornames, $userinfo,
553                             get_string('gradegivento', 'workshop'));
554                     $cell->rowspan = $spangiven;
555                     $cell->add_class('givengrade');
556                     if (is_null($assessment) or is_null($assessment->grade)) {
557                         $cell->add_class('null');
558                     } else {
559                         $cell->add_class('notnull');
560                     }
561                     $row->cells[] = $cell;
562                 }
563                 // column #6 - total grade for assessment
564                 if ($options->showgradinggrade and $tr == 0) {
565                     $cell = new html_table_cell();
566                     $cell->text = $this->grading_report_grade($participant->gradinggrade);
567                     $cell->rowspan = $numoftrs;
568                     $cell->add_class('gradinggrade');
569                     $row->cells[] = $cell;
570                 }
572                 $table->data[] = $row;
573             }
574         }
576         return $this->output->table($table);
577     }
579     /**
580      * Renders a text with icons to sort by the given column
581      *
582      * This is intended for table headings.
583      *
584      * @param string $text    The heading text
585      * @param string $sortid  The column id used for sorting
586      * @param string $sortby  Currently sorted by (column id)
587      * @param string $sorthow Currently sorted how (ASC|DESC)
588      *
589      * @return string
590      */
591     protected function sortable_heading($text, $sortid=null, $sortby=null, $sorthow=null) {
592         global $PAGE;
594         $out = html_writer::tag('span', $text, array('class'=>'text'));
596         if (!is_null($sortid)) {
597             if ($sortby !== $sortid or $sorthow !== 'ASC') {
598                 $url = new moodle_url($PAGE->url);
599                 $url->params(array('sortby' => $sortid, 'sorthow' => 'ASC'));
600                 $out .= $this->output->action_icon($url, new pix_icon('t/up', get_string('sortasc', 'workshop')), null, array('class' => 'sort asc'));
601             }
602             if ($sortby !== $sortid or $sorthow !== 'DESC') {
603                 $url = new moodle_url($PAGE->url);
604                 $url->params(array('sortby' => $sortid, 'sorthow' => 'DESC'));
605                 $out .= $this->output->action_icon($url, new pix_icon('t/down', get_string('sortdesc', 'workshop')), null, array('class' => 'sort desc'));
606             }
607         }
608         return $out;
611     /**
612      * @param stdclass $participant
613      * @param array $userinfo
614      * @return string
615      */
616     protected function grading_report_participant(stdclass $participant, array $userinfo) {
617         $userid = $participant->userid;
618         $out  = $this->output->user_picture($userinfo[$userid], array('courseid' => $this->page->course->id, 'size' => 35));
619         $out .= html_writer::tag('span', fullname($userinfo[$userid]));
621         return $out;
622     }
624     /**
625      * @param stdclass $participant
626      * @return string
627      */
628     protected function grading_report_submission(stdclass $participant) {
629         global $CFG;
631         if (is_null($participant->submissionid)) {
632             $out = $this->output->container(get_string('nosubmissionfound', 'workshop'), 'info');
633         } else {
634             $url = new moodle_url('/mod/workshop/submission.php',
635                                   array('cmid' => $this->page->context->instanceid, 'id' => $participant->submissionid));
636             $out = html_writer::link($url, format_string($participant->submissiontitle), array('class'=>'title'));
637         }
639         return $out;
640     }
642     /**
643      * @todo Highlight the nulls
644      * @param stdclass|null $assessment
645      * @param bool $shownames
646      * @param string $separator between the grade and the reviewer/author
647      * @return string
648      */
649     protected function grading_report_assessment($assessment, $shownames, array $userinfo, $separator) {
650         global $CFG;
652         if (is_null($assessment)) {
653             return get_string('nullgrade', 'workshop');
654         }
655         $a = new stdclass();
656         $a->grade = is_null($assessment->grade) ? get_string('nullgrade', 'workshop') : $assessment->grade;
657         $a->gradinggrade = is_null($assessment->gradinggrade) ? get_string('nullgrade', 'workshop') : $assessment->gradinggrade;
658         $a->weight = $assessment->weight;
659         // grrr the following logic should really be handled by a future language pack feature
660         if (is_null($assessment->gradinggradeover)) {
661             if ($a->weight == 1) {
662                 $grade = get_string('formatpeergrade', 'workshop', $a);
663             } else {
664                 $grade = get_string('formatpeergradeweighted', 'workshop', $a);
665             }
666         } else {
667             $a->gradinggradeover = $assessment->gradinggradeover;
668             if ($a->weight == 1) {
669                 $grade = get_string('formatpeergradeover', 'workshop', $a);
670             } else {
671                 $grade = get_string('formatpeergradeoverweighted', 'workshop', $a);
672             }
673         }
674         $url = new moodle_url('/mod/workshop/assessment.php',
675                               array('asid' => $assessment->assessmentid));
676         $grade = html_writer::link($url, $grade, array('class'=>'grade'));
678         if ($shownames) {
679             $userid = $assessment->userid;
680             $name   = $this->output->user_picture($userinfo[$userid], array('courseid' => $this->page->course->id, 'size' => 16));
681             $name  .= html_writer::tag('span', fullname($userinfo[$userid]), array('class' => 'fullname'));
682             $name   = $separator . html_writer::tag('span', $name, array('class' => 'user'));
683         } else {
684             $name   = '';
685         }
687         return $this->output->container($grade . $name, 'assessmentdetails');
688     }
690     /**
691      * Formats the aggreagated grades
692      */
693     protected function grading_report_grade($grade, $over=null) {
694         $a = new stdclass();
695         $a->grade = is_null($grade) ? get_string('nullgrade', 'workshop') : $grade;
696         if (is_null($over)) {
697             $text = get_string('formataggregatedgrade', 'workshop', $a);
698         } else {
699             $a->over = is_null($over) ? get_string('nullgrade', 'workshop') : $over;
700             $text = get_string('formataggregatedgradeover', 'workshop', $a);
701         }
702         return $text;
703     }
705     ////////////////////////////////////////////////////////////////////////////
706     // Helper methods                                                         //
707     ////////////////////////////////////////////////////////////////////////////
709     /**
710      * Helper function returning the n-th item of the array
711      *
712      * @param array $a
713      * @param int   $n from 0 to m, where m is th number of items in the array
714      * @return mixed the $n-th element of $a
715      */
716     protected static function array_nth(array $a, $n) {
717         $keys = array_keys($a);
718         if ($n < 0 or $n > count($keys) - 1) {
719             return null;
720         }
721         $key = $keys[$n];
722         return $a[$key];
723     }
725     /**
726      * Tries to guess the fullname format set at the site
727      *
728      * @return string fl|lf
729      */
730     protected static function fullname_format() {
731         $fake = new stdclass(); // fake user
732         $fake->lastname = 'LLLL';
733         $fake->firstname = 'FFFF';
734         $fullname = get_string('fullnamedisplay', '', $fake);
735         if (strpos($fullname, 'LLLL') < strpos($fullname, 'FFFF')) {
736             return 'lf';
737         } else {
738             return 'fl';
739         }
740     }