PageRenderTime 110ms CodeModel.GetById 23ms app.highlight 69ms RepoModel.GetById 1ms app.codeStats 1ms

/mod/workshop/renderer.php

http://github.com/moodle/moodle
PHP | 1160 lines | 769 code | 165 blank | 226 comment | 151 complexity | 0525e0e3accbb653b0249b0164762e49 MD5 | raw file
   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/>.
  17
  18/**
  19 * Workshop module renderering methods 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 */
  25
  26defined('MOODLE_INTERNAL') || die();
  27
  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 */
  34class mod_workshop_renderer extends plugin_renderer_base {
  35
  36    ////////////////////////////////////////////////////////////////////////////
  37    // External API - methods to render workshop renderable components
  38    ////////////////////////////////////////////////////////////////////////////
  39
  40    /**
  41     * Renders workshop message
  42     *
  43     * @param workshop_message $message to display
  44     * @return string html code
  45     */
  46    protected function render_workshop_message(workshop_message $message) {
  47
  48        $text   = $message->get_message();
  49        $url    = $message->get_action_url();
  50        $label  = $message->get_action_label();
  51
  52        if (empty($text) and empty($label)) {
  53            return '';
  54        }
  55
  56        switch ($message->get_type()) {
  57        case workshop_message::TYPE_OK:
  58            $sty = 'ok';
  59            break;
  60        case workshop_message::TYPE_ERROR:
  61            $sty = 'error';
  62            break;
  63        default:
  64            $sty = 'info';
  65        }
  66
  67        $o = html_writer::tag('span', $message->get_message());
  68
  69        if (!is_null($url) and !is_null($label)) {
  70            $o .= $this->output->single_button($url, $label, 'get');
  71        }
  72
  73        return $this->output->container($o, array('message', $sty));
  74    }
  75
  76
  77    /**
  78     * Renders full workshop submission
  79     *
  80     * @param workshop_submission $submission
  81     * @return string HTML
  82     */
  83    protected function render_workshop_submission(workshop_submission $submission) {
  84        global $CFG;
  85
  86        $o  = '';    // output HTML code
  87        $anonymous = $submission->is_anonymous();
  88        $classes = 'submission-full';
  89        if ($anonymous) {
  90            $classes .= ' anonymous';
  91        }
  92        $o .= $this->output->container_start($classes);
  93        $o .= $this->output->container_start('header');
  94
  95        $title = format_string($submission->title);
  96
  97        if ($this->page->url != $submission->url) {
  98            $title = html_writer::link($submission->url, $title);
  99        }
 100
 101        $o .= $this->output->heading($title, 3, 'title');
 102
 103        if (!$anonymous) {
 104            $author = new stdclass();
 105            $additionalfields = explode(',', user_picture::fields());
 106            $author = username_load_fields_from_object($author, $submission, 'author', $additionalfields);
 107            $userpic            = $this->output->user_picture($author, array('courseid' => $this->page->course->id, 'size' => 64));
 108            $userurl            = new moodle_url('/user/view.php',
 109                                            array('id' => $author->id, 'course' => $this->page->course->id));
 110            $a                  = new stdclass();
 111            $a->name            = fullname($author);
 112            $a->url             = $userurl->out();
 113            $byfullname         = get_string('byfullname', 'workshop', $a);
 114            $oo  = $this->output->container($userpic, 'picture');
 115            $oo .= $this->output->container($byfullname, 'fullname');
 116
 117            $o .= $this->output->container($oo, 'author');
 118        }
 119
 120        $created = get_string('userdatecreated', 'workshop', userdate($submission->timecreated));
 121        $o .= $this->output->container($created, 'userdate created');
 122
 123        if ($submission->timemodified > $submission->timecreated) {
 124            $modified = get_string('userdatemodified', 'workshop', userdate($submission->timemodified));
 125            $o .= $this->output->container($modified, 'userdate modified');
 126        }
 127
 128        $o .= $this->output->container_end(); // end of header
 129
 130        $content = file_rewrite_pluginfile_urls($submission->content, 'pluginfile.php', $this->page->context->id,
 131                                                        'mod_workshop', 'submission_content', $submission->id);
 132        $content = format_text($content, $submission->contentformat, array('overflowdiv'=>true));
 133        if (!empty($content)) {
 134            if (!empty($CFG->enableplagiarism)) {
 135                require_once($CFG->libdir.'/plagiarismlib.php');
 136                $content .= plagiarism_get_links(array('userid' => $submission->authorid,
 137                    'content' => $submission->content,
 138                    'cmid' => $this->page->cm->id,
 139                    'course' => $this->page->course));
 140            }
 141        }
 142        $o .= $this->output->container($content, 'content');
 143
 144        $o .= $this->helper_submission_attachments($submission->id, 'html');
 145
 146        $o .= $this->output->container_end(); // end of submission-full
 147
 148        return $o;
 149    }
 150
 151    /**
 152     * Renders short summary of the submission
 153     *
 154     * @param workshop_submission_summary $summary
 155     * @return string text to be echo'ed
 156     */
 157    protected function render_workshop_submission_summary(workshop_submission_summary $summary) {
 158
 159        $o  = '';    // output HTML code
 160        $anonymous = $summary->is_anonymous();
 161        $classes = 'submission-summary';
 162
 163        if ($anonymous) {
 164            $classes .= ' anonymous';
 165        }
 166
 167        $gradestatus = '';
 168
 169        if ($summary->status == 'notgraded') {
 170            $classes    .= ' notgraded';
 171            $gradestatus = $this->output->container(get_string('nogradeyet', 'workshop'), 'grade-status');
 172
 173        } else if ($summary->status == 'graded') {
 174            $classes    .= ' graded';
 175            $gradestatus = $this->output->container(get_string('alreadygraded', 'workshop'), 'grade-status');
 176        }
 177
 178        $o .= $this->output->container_start($classes);  // main wrapper
 179        $o .= html_writer::link($summary->url, format_string($summary->title), array('class' => 'title'));
 180
 181        if (!$anonymous) {
 182            $author             = new stdClass();
 183            $additionalfields = explode(',', user_picture::fields());
 184            $author = username_load_fields_from_object($author, $summary, 'author', $additionalfields);
 185            $userpic            = $this->output->user_picture($author, array('courseid' => $this->page->course->id, 'size' => 35));
 186            $userurl            = new moodle_url('/user/view.php',
 187                                            array('id' => $author->id, 'course' => $this->page->course->id));
 188            $a                  = new stdClass();
 189            $a->name            = fullname($author);
 190            $a->url             = $userurl->out();
 191            $byfullname         = get_string('byfullname', 'workshop', $a);
 192
 193            $oo  = $this->output->container($userpic, 'picture');
 194            $oo .= $this->output->container($byfullname, 'fullname');
 195            $o  .= $this->output->container($oo, 'author');
 196        }
 197
 198        $created = get_string('userdatecreated', 'workshop', userdate($summary->timecreated));
 199        $o .= $this->output->container($created, 'userdate created');
 200
 201        if ($summary->timemodified > $summary->timecreated) {
 202            $modified = get_string('userdatemodified', 'workshop', userdate($summary->timemodified));
 203            $o .= $this->output->container($modified, 'userdate modified');
 204        }
 205
 206        $o .= $gradestatus;
 207        $o .= $this->output->container_end(); // end of the main wrapper
 208        return $o;
 209    }
 210
 211    /**
 212     * Renders full workshop example submission
 213     *
 214     * @param workshop_example_submission $example
 215     * @return string HTML
 216     */
 217    protected function render_workshop_example_submission(workshop_example_submission $example) {
 218
 219        $o  = '';    // output HTML code
 220        $classes = 'submission-full example';
 221        $o .= $this->output->container_start($classes);
 222        $o .= $this->output->container_start('header');
 223        $o .= $this->output->container(format_string($example->title), array('class' => 'title'));
 224        $o .= $this->output->container_end(); // end of header
 225
 226        $content = file_rewrite_pluginfile_urls($example->content, 'pluginfile.php', $this->page->context->id,
 227                                                        'mod_workshop', 'submission_content', $example->id);
 228        $content = format_text($content, $example->contentformat, array('overflowdiv'=>true));
 229        $o .= $this->output->container($content, 'content');
 230
 231        $o .= $this->helper_submission_attachments($example->id, 'html');
 232
 233        $o .= $this->output->container_end(); // end of submission-full
 234
 235        return $o;
 236    }
 237
 238    /**
 239     * Renders short summary of the example submission
 240     *
 241     * @param workshop_example_submission_summary $summary
 242     * @return string text to be echo'ed
 243     */
 244    protected function render_workshop_example_submission_summary(workshop_example_submission_summary $summary) {
 245
 246        $o  = '';    // output HTML code
 247
 248        // wrapping box
 249        $o .= $this->output->box_start('generalbox example-summary ' . $summary->status);
 250
 251        // title
 252        $o .= $this->output->container_start('example-title');
 253        $o .= html_writer::link($summary->url, format_string($summary->title), array('class' => 'title'));
 254
 255        if ($summary->editable) {
 256            $o .= $this->output->action_icon($summary->editurl, new pix_icon('i/edit', get_string('edit')));
 257        }
 258        $o .= $this->output->container_end();
 259
 260        // additional info
 261        if ($summary->status == 'notgraded') {
 262            $o .= $this->output->container(get_string('nogradeyet', 'workshop'), 'example-info nograde');
 263        } else {
 264            $o .= $this->output->container(get_string('gradeinfo', 'workshop' , $summary->gradeinfo), 'example-info grade');
 265        }
 266
 267        // button to assess
 268        $button = new single_button($summary->assessurl, $summary->assesslabel, 'get');
 269        $o .= $this->output->container($this->output->render($button), 'example-actions');
 270
 271        // end of wrapping box
 272        $o .= $this->output->box_end();
 273
 274        return $o;
 275    }
 276
 277    /**
 278     * Renders the user plannner tool
 279     *
 280     * @param workshop_user_plan $plan prepared for the user
 281     * @return string html code to be displayed
 282     */
 283    protected function render_workshop_user_plan(workshop_user_plan $plan) {
 284        $o  = '';    // Output HTML code.
 285        $numberofphases = count($plan->phases);
 286        $o .= html_writer::start_tag('div', array(
 287            'class' => 'userplan',
 288            'aria-labelledby' => 'mod_workshop-userplanheading',
 289            'aria-describedby' => 'mod_workshop-userplanaccessibilitytitle',
 290        ));
 291        $o .= html_writer::span(get_string('userplanaccessibilitytitle', 'workshop', $numberofphases),
 292            'accesshide', array('id' => 'mod_workshop-userplanaccessibilitytitle'));
 293        $o .= html_writer::link('#mod_workshop-userplancurrenttasks', get_string('userplanaccessibilityskip', 'workshop'),
 294            array('class' => 'accesshide'));
 295        foreach ($plan->phases as $phasecode => $phase) {
 296            $o .= html_writer::start_tag('dl', array('class' => 'phase'));
 297            $actions = '';
 298
 299            if ($phase->active) {
 300                // Mark the section as the current one.
 301                $icon = $this->output->pix_icon('i/marked', '', 'moodle', ['role' => 'presentation']);
 302                $actions .= get_string('userplancurrentphase', 'workshop').' '.$icon;
 303
 304            } else {
 305                // Display a control widget to switch to the given phase or mark the phase as the current one.
 306                foreach ($phase->actions as $action) {
 307                    if ($action->type === 'switchphase') {
 308                        if ($phasecode == workshop::PHASE_ASSESSMENT && $plan->workshop->phase == workshop::PHASE_SUBMISSION
 309                                && $plan->workshop->phaseswitchassessment) {
 310                            $icon = new pix_icon('i/scheduled', get_string('switchphaseauto', 'mod_workshop'));
 311                        } else {
 312                            $icon = new pix_icon('i/marker', get_string('switchphase'.$phasecode, 'mod_workshop'));
 313                        }
 314                        $actions .= $this->output->action_icon($action->url, $icon, null, null, true);
 315                    }
 316                }
 317            }
 318
 319            if (!empty($actions)) {
 320                $actions = $this->output->container($actions, 'actions');
 321            }
 322            $classes = 'phase' . $phasecode;
 323            if ($phase->active) {
 324                $title = html_writer::span($phase->title, 'phasetitle', ['id' => 'mod_workshop-userplancurrenttasks']);
 325                $classes .= ' active';
 326            } else {
 327                $title = html_writer::span($phase->title, 'phasetitle');
 328                $classes .= ' nonactive';
 329            }
 330            $o .= html_writer::start_tag('dt', array('class' => $classes));
 331            $o .= $this->output->container($title . $actions);
 332            $o .= html_writer::start_tag('dd', array('class' => $classes. ' phasetasks'));
 333            $o .= $this->helper_user_plan_tasks($phase->tasks);
 334            $o .= html_writer::end_tag('dd');
 335            $o .= html_writer::end_tag('dl');
 336        }
 337        $o .= html_writer::end_tag('div');
 338        return $o;
 339    }
 340
 341    /**
 342     * Renders the result of the submissions allocation process
 343     *
 344     * @param workshop_allocation_result $result as returned by the allocator's init() method
 345     * @return string HTML to be echoed
 346     */
 347    protected function render_workshop_allocation_result(workshop_allocation_result $result) {
 348        global $CFG;
 349
 350        $status = $result->get_status();
 351
 352        if (is_null($status) or $status == workshop_allocation_result::STATUS_VOID) {
 353            debugging('Attempt to render workshop_allocation_result with empty status', DEBUG_DEVELOPER);
 354            return '';
 355        }
 356
 357        switch ($status) {
 358        case workshop_allocation_result::STATUS_FAILED:
 359            if ($message = $result->get_message()) {
 360                $message = new workshop_message($message, workshop_message::TYPE_ERROR);
 361            } else {
 362                $message = new workshop_message(get_string('allocationerror', 'workshop'), workshop_message::TYPE_ERROR);
 363            }
 364            break;
 365
 366        case workshop_allocation_result::STATUS_CONFIGURED:
 367            if ($message = $result->get_message()) {
 368                $message = new workshop_message($message, workshop_message::TYPE_INFO);
 369            } else {
 370                $message = new workshop_message(get_string('allocationconfigured', 'workshop'), workshop_message::TYPE_INFO);
 371            }
 372            break;
 373
 374        case workshop_allocation_result::STATUS_EXECUTED:
 375            if ($message = $result->get_message()) {
 376                $message = new workshop_message($message, workshop_message::TYPE_OK);
 377            } else {
 378                $message = new workshop_message(get_string('allocationdone', 'workshop'), workshop_message::TYPE_OK);
 379            }
 380            break;
 381
 382        default:
 383            throw new coding_exception('Unknown allocation result status', $status);
 384        }
 385
 386        // start with the message
 387        $o = $this->render($message);
 388
 389        // display the details about the process if available
 390        $logs = $result->get_logs();
 391        if (is_array($logs) and !empty($logs)) {
 392            $o .= html_writer::start_tag('ul', array('class' => 'allocation-init-results'));
 393            foreach ($logs as $log) {
 394                if ($log->type == 'debug' and !$CFG->debugdeveloper) {
 395                    // display allocation debugging messages for developers only
 396                    continue;
 397                }
 398                $class = $log->type;
 399                if ($log->indent) {
 400                    $class .= ' indent';
 401                }
 402                $o .= html_writer::tag('li', $log->message, array('class' => $class)).PHP_EOL;
 403            }
 404            $o .= html_writer::end_tag('ul');
 405        }
 406
 407        return $o;
 408    }
 409
 410    /**
 411     * Renders the workshop grading report
 412     *
 413     * @param workshop_grading_report $gradingreport
 414     * @return string html code
 415     */
 416    protected function render_workshop_grading_report(workshop_grading_report $gradingreport) {
 417
 418        $data       = $gradingreport->get_data();
 419        $options    = $gradingreport->get_options();
 420        $grades     = $data->grades;
 421        $userinfo   = $data->userinfo;
 422
 423        if (empty($grades)) {
 424            return '';
 425        }
 426
 427        $table = new html_table();
 428        $table->attributes['class'] = 'grading-report table-striped table-hover';
 429
 430        $sortbyfirstname = $this->helper_sortable_heading(get_string('firstname'), 'firstname', $options->sortby, $options->sorthow);
 431        $sortbylastname = $this->helper_sortable_heading(get_string('lastname'), 'lastname', $options->sortby, $options->sorthow);
 432        if (self::fullname_format() == 'lf') {
 433            $sortbyname = $sortbylastname . ' / ' . $sortbyfirstname;
 434        } else {
 435            $sortbyname = $sortbyfirstname . ' / ' . $sortbylastname;
 436        }
 437
 438        $sortbysubmisstiontitle = $this->helper_sortable_heading(get_string('submission', 'workshop'), 'submissiontitle',
 439                $options->sortby, $options->sorthow);
 440        $sortbysubmisstionlastmodified = $this->helper_sortable_heading(get_string('submissionlastmodified', 'workshop'),
 441                'submissionmodified', $options->sortby, $options->sorthow);
 442        $sortbysubmisstion = $sortbysubmisstiontitle . ' / ' . $sortbysubmisstionlastmodified;
 443
 444        $table->head = array();
 445        $table->head[] = $sortbyname;
 446        $table->head[] = $sortbysubmisstion;
 447
 448        // If we are in submission phase ignore the following headers (columns).
 449        if ($options->workshopphase != workshop::PHASE_SUBMISSION) {
 450            $table->head[] = $this->helper_sortable_heading(get_string('receivedgrades', 'workshop'));
 451            if ($options->showsubmissiongrade) {
 452                $table->head[] = $this->helper_sortable_heading(get_string('submissiongradeof', 'workshop', $data->maxgrade),
 453                        'submissiongrade', $options->sortby, $options->sorthow);
 454            }
 455            $table->head[] = $this->helper_sortable_heading(get_string('givengrades', 'workshop'));
 456            if ($options->showgradinggrade) {
 457                $table->head[] = $this->helper_sortable_heading(get_string('gradinggradeof', 'workshop', $data->maxgradinggrade),
 458                        'gradinggrade', $options->sortby, $options->sorthow);
 459            }
 460        }
 461        $table->rowclasses  = array();
 462        $table->colclasses  = array();
 463        $table->data        = array();
 464
 465        foreach ($grades as $participant) {
 466            $numofreceived  = count($participant->reviewedby);
 467            $numofgiven     = count($participant->reviewerof);
 468            $published      = $participant->submissionpublished;
 469
 470            // compute the number of <tr> table rows needed to display this participant
 471            if ($numofreceived > 0 and $numofgiven > 0) {
 472                $numoftrs       = workshop::lcm($numofreceived, $numofgiven);
 473                $spanreceived   = $numoftrs / $numofreceived;
 474                $spangiven      = $numoftrs / $numofgiven;
 475            } elseif ($numofreceived == 0 and $numofgiven > 0) {
 476                $numoftrs       = $numofgiven;
 477                $spanreceived   = $numoftrs;
 478                $spangiven      = $numoftrs / $numofgiven;
 479            } elseif ($numofreceived > 0 and $numofgiven == 0) {
 480                $numoftrs       = $numofreceived;
 481                $spanreceived   = $numoftrs / $numofreceived;
 482                $spangiven      = $numoftrs;
 483            } else {
 484                $numoftrs       = 1;
 485                $spanreceived   = 1;
 486                $spangiven      = 1;
 487            }
 488
 489            for ($tr = 0; $tr < $numoftrs; $tr++) {
 490                $row = new html_table_row();
 491                if ($published) {
 492                    $row->attributes['class'] = 'published';
 493                }
 494                // column #1 - participant - spans over all rows
 495                if ($tr == 0) {
 496                    $cell = new html_table_cell();
 497                    $cell->text = $this->helper_grading_report_participant($participant, $userinfo);
 498                    $cell->rowspan = $numoftrs;
 499                    $cell->attributes['class'] = 'participant';
 500                    $row->cells[] = $cell;
 501                }
 502                // column #2 - submission - spans over all rows
 503                if ($tr == 0) {
 504                    $cell = new html_table_cell();
 505                    $cell->text = $this->helper_grading_report_submission($participant);
 506                    $cell->rowspan = $numoftrs;
 507                    $cell->attributes['class'] = 'submission';
 508                    $row->cells[] = $cell;
 509                }
 510
 511                // If we are in submission phase ignore the following columns.
 512                if ($options->workshopphase == workshop::PHASE_SUBMISSION) {
 513                    $table->data[] = $row;
 514                    continue;
 515                }
 516
 517                // column #3 - received grades
 518                if ($tr % $spanreceived == 0) {
 519                    $idx = intval($tr / $spanreceived);
 520                    $assessment = self::array_nth($participant->reviewedby, $idx);
 521                    $cell = new html_table_cell();
 522                    $cell->text = $this->helper_grading_report_assessment($assessment, $options->showreviewernames, $userinfo,
 523                            get_string('gradereceivedfrom', 'workshop'));
 524                    $cell->rowspan = $spanreceived;
 525                    $cell->attributes['class'] = 'receivedgrade';
 526                    if (is_null($assessment) or is_null($assessment->grade)) {
 527                        $cell->attributes['class'] .= ' null';
 528                    } else {
 529                        $cell->attributes['class'] .= ' notnull';
 530                    }
 531                    $row->cells[] = $cell;
 532                }
 533                // column #4 - total grade for submission
 534                if ($options->showsubmissiongrade and $tr == 0) {
 535                    $cell = new html_table_cell();
 536                    $cell->text = $this->helper_grading_report_grade($participant->submissiongrade, $participant->submissiongradeover);
 537                    $cell->rowspan = $numoftrs;
 538                    $cell->attributes['class'] = 'submissiongrade';
 539                    $row->cells[] = $cell;
 540                }
 541                // column #5 - given grades
 542                if ($tr % $spangiven == 0) {
 543                    $idx = intval($tr / $spangiven);
 544                    $assessment = self::array_nth($participant->reviewerof, $idx);
 545                    $cell = new html_table_cell();
 546                    $cell->text = $this->helper_grading_report_assessment($assessment, $options->showauthornames, $userinfo,
 547                            get_string('gradegivento', 'workshop'));
 548                    $cell->rowspan = $spangiven;
 549                    $cell->attributes['class'] = 'givengrade';
 550                    if (is_null($assessment) or is_null($assessment->grade)) {
 551                        $cell->attributes['class'] .= ' null';
 552                    } else {
 553                        $cell->attributes['class'] .= ' notnull';
 554                    }
 555                    $row->cells[] = $cell;
 556                }
 557                // column #6 - total grade for assessment
 558                if ($options->showgradinggrade and $tr == 0) {
 559                    $cell = new html_table_cell();
 560                    $cell->text = $this->helper_grading_report_grade($participant->gradinggrade);
 561                    $cell->rowspan = $numoftrs;
 562                    $cell->attributes['class'] = 'gradinggrade';
 563                    $row->cells[] = $cell;
 564                }
 565
 566                $table->data[] = $row;
 567            }
 568        }
 569
 570        return html_writer::table($table);
 571    }
 572
 573    /**
 574     * Renders the feedback for the author of the submission
 575     *
 576     * @param workshop_feedback_author $feedback
 577     * @return string HTML
 578     */
 579    protected function render_workshop_feedback_author(workshop_feedback_author $feedback) {
 580        return $this->helper_render_feedback($feedback);
 581    }
 582
 583    /**
 584     * Renders the feedback for the reviewer of the submission
 585     *
 586     * @param workshop_feedback_reviewer $feedback
 587     * @return string HTML
 588     */
 589    protected function render_workshop_feedback_reviewer(workshop_feedback_reviewer $feedback) {
 590        return $this->helper_render_feedback($feedback);
 591    }
 592
 593    /**
 594     * Helper method to rendering feedback
 595     *
 596     * @param workshop_feedback_author|workshop_feedback_reviewer $feedback
 597     * @return string HTML
 598     */
 599    private function helper_render_feedback($feedback) {
 600
 601        $o  = '';    // output HTML code
 602        $o .= $this->output->container_start('feedback feedbackforauthor');
 603        $o .= $this->output->container_start('header');
 604        $o .= $this->output->heading(get_string('feedbackby', 'workshop', s(fullname($feedback->get_provider()))), 3, 'title');
 605
 606        $userpic = $this->output->user_picture($feedback->get_provider(), array('courseid' => $this->page->course->id, 'size' => 32));
 607        $o .= $this->output->container($userpic, 'picture');
 608        $o .= $this->output->container_end(); // end of header
 609
 610        $content = format_text($feedback->get_content(), $feedback->get_format(), array('overflowdiv' => true));
 611        $o .= $this->output->container($content, 'content');
 612
 613        $o .= $this->output->container_end();
 614
 615        return $o;
 616    }
 617
 618    /**
 619     * Renders the full assessment
 620     *
 621     * @param workshop_assessment $assessment
 622     * @return string HTML
 623     */
 624    protected function render_workshop_assessment(workshop_assessment $assessment) {
 625
 626        $o = ''; // output HTML code
 627        $anonymous = is_null($assessment->reviewer);
 628        $classes = 'assessment-full';
 629        if ($anonymous) {
 630            $classes .= ' anonymous';
 631        }
 632
 633        $o .= $this->output->container_start($classes);
 634        $o .= $this->output->container_start('header');
 635
 636        if (!empty($assessment->title)) {
 637            $title = s($assessment->title);
 638        } else {
 639            $title = get_string('assessment', 'workshop');
 640        }
 641        if (($assessment->url instanceof moodle_url) and ($this->page->url != $assessment->url)) {
 642            $o .= $this->output->container(html_writer::link($assessment->url, $title), 'title');
 643        } else {
 644            $o .= $this->output->container($title, 'title');
 645        }
 646
 647        if (!$anonymous) {
 648            $reviewer   = $assessment->reviewer;
 649            $userpic    = $this->output->user_picture($reviewer, array('courseid' => $this->page->course->id, 'size' => 32));
 650
 651            $userurl    = new moodle_url('/user/view.php',
 652                                       array('id' => $reviewer->id, 'course' => $this->page->course->id));
 653            $a          = new stdClass();
 654            $a->name    = fullname($reviewer);
 655            $a->url     = $userurl->out();
 656            $byfullname = get_string('assessmentby', 'workshop', $a);
 657            $oo         = $this->output->container($userpic, 'picture');
 658            $oo        .= $this->output->container($byfullname, 'fullname');
 659
 660            $o .= $this->output->container($oo, 'reviewer');
 661        }
 662
 663        if (is_null($assessment->realgrade)) {
 664            $o .= $this->output->container(
 665                get_string('notassessed', 'workshop'),
 666                'grade nograde'
 667            );
 668        } else {
 669            $a              = new stdClass();
 670            $a->max         = $assessment->maxgrade;
 671            $a->received    = $assessment->realgrade;
 672            $o .= $this->output->container(
 673                get_string('gradeinfo', 'workshop', $a),
 674                'grade'
 675            );
 676
 677            if (!is_null($assessment->weight) and $assessment->weight != 1) {
 678                $o .= $this->output->container(
 679                    get_string('weightinfo', 'workshop', $assessment->weight),
 680                    'weight'
 681                );
 682            }
 683        }
 684
 685        $o .= $this->output->container_start('actions');
 686        foreach ($assessment->actions as $action) {
 687            $o .= $this->output->single_button($action->url, $action->label, $action->method);
 688        }
 689        $o .= $this->output->container_end(); // actions
 690
 691        $o .= $this->output->container_end(); // header
 692
 693        if (!is_null($assessment->form)) {
 694            $o .= print_collapsible_region_start('assessment-form-wrapper', uniqid('workshop-assessment'),
 695                    get_string('assessmentform', 'workshop'), '', false, true);
 696            $o .= $this->output->container(self::moodleform($assessment->form), 'assessment-form');
 697            $o .= print_collapsible_region_end(true);
 698
 699            if (!$assessment->form->is_editable()) {
 700                $o .= $this->overall_feedback($assessment);
 701            }
 702        }
 703
 704        $o .= $this->output->container_end(); // main wrapper
 705
 706        return $o;
 707    }
 708
 709    /**
 710     * Renders the assessment of an example submission
 711     *
 712     * @param workshop_example_assessment $assessment
 713     * @return string HTML
 714     */
 715    protected function render_workshop_example_assessment(workshop_example_assessment $assessment) {
 716        return $this->render_workshop_assessment($assessment);
 717    }
 718
 719    /**
 720     * Renders the reference assessment of an example submission
 721     *
 722     * @param workshop_example_reference_assessment $assessment
 723     * @return string HTML
 724     */
 725    protected function render_workshop_example_reference_assessment(workshop_example_reference_assessment $assessment) {
 726        return $this->render_workshop_assessment($assessment);
 727    }
 728
 729    /**
 730     * Renders the overall feedback for the author of the submission
 731     *
 732     * @param workshop_assessment $assessment
 733     * @return string HTML
 734     */
 735    protected function overall_feedback(workshop_assessment $assessment) {
 736
 737        $content = $assessment->get_overall_feedback_content();
 738
 739        if ($content === false) {
 740            return '';
 741        }
 742
 743        $o = '';
 744
 745        if (!is_null($content)) {
 746            $o .= $this->output->container($content, 'content');
 747        }
 748
 749        $attachments = $assessment->get_overall_feedback_attachments();
 750
 751        if (!empty($attachments)) {
 752            $o .= $this->output->container_start('attachments');
 753            $images = '';
 754            $files = '';
 755            foreach ($attachments as $attachment) {
 756                $icon = $this->output->pix_icon(file_file_icon($attachment), get_mimetype_description($attachment),
 757                    'moodle', array('class' => 'icon'));
 758                $link = html_writer::link($attachment->fileurl, $icon.' '.substr($attachment->filepath.$attachment->filename, 1));
 759                if (file_mimetype_in_typegroup($attachment->mimetype, 'web_image')) {
 760                    $preview = html_writer::empty_tag('img', array('src' => $attachment->previewurl, 'alt' => '', 'class' => 'preview'));
 761                    $preview = html_writer::tag('a', $preview, array('href' => $attachment->fileurl));
 762                    $images .= $this->output->container($preview);
 763                } else {
 764                    $files .= html_writer::tag('li', $link, array('class' => $attachment->mimetype));
 765                }
 766            }
 767            if ($images) {
 768                $images = $this->output->container($images, 'images');
 769            }
 770
 771            if ($files) {
 772                $files = html_writer::tag('ul', $files, array('class' => 'files'));
 773            }
 774
 775            $o .= $images.$files;
 776            $o .= $this->output->container_end();
 777        }
 778
 779        if ($o === '') {
 780            return '';
 781        }
 782
 783        $o = $this->output->box($o, 'overallfeedback');
 784        $o = print_collapsible_region($o, 'overall-feedback-wrapper', uniqid('workshop-overall-feedback'),
 785            get_string('overallfeedback', 'workshop'), '', false, true);
 786
 787        return $o;
 788    }
 789
 790    /**
 791     * Renders a perpage selector for workshop listings
 792     *
 793     * The scripts using this have to define the $PAGE->url prior to calling this
 794     * and deal with eventually submitted value themselves.
 795     *
 796     * @param int $current current value of the perpage parameter
 797     * @return string HTML
 798     */
 799    public function perpage_selector($current=10) {
 800
 801        $options = array();
 802        foreach (array(10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 200, 300, 400, 500, 1000) as $option) {
 803            if ($option != $current) {
 804                $options[$option] = $option;
 805            }
 806        }
 807        $select = new single_select($this->page->url, 'perpage', $options, '', array('' => get_string('showingperpagechange', 'mod_workshop')));
 808        $select->label = get_string('showingperpage', 'mod_workshop', $current);
 809        $select->method = 'post';
 810
 811        return $this->output->container($this->output->render($select), 'perpagewidget');
 812    }
 813
 814    /**
 815     * Renders the user's final grades
 816     *
 817     * @param workshop_final_grades $grades with the info about grades in the gradebook
 818     * @return string HTML
 819     */
 820    protected function render_workshop_final_grades(workshop_final_grades $grades) {
 821
 822        $out = html_writer::start_tag('div', array('class' => 'finalgrades'));
 823
 824        if (!empty($grades->submissiongrade)) {
 825            $cssclass = 'grade submissiongrade';
 826            if ($grades->submissiongrade->hidden) {
 827                $cssclass .= ' hiddengrade';
 828            }
 829            $out .= html_writer::tag(
 830                'div',
 831                html_writer::tag('div', get_string('submissiongrade', 'mod_workshop'), array('class' => 'gradetype')) .
 832                html_writer::tag('div', $grades->submissiongrade->str_long_grade, array('class' => 'gradevalue')),
 833                array('class' => $cssclass)
 834            );
 835        }
 836
 837        if (!empty($grades->assessmentgrade)) {
 838            $cssclass = 'grade assessmentgrade';
 839            if ($grades->assessmentgrade->hidden) {
 840                $cssclass .= ' hiddengrade';
 841            }
 842            $out .= html_writer::tag(
 843                'div',
 844                html_writer::tag('div', get_string('gradinggrade', 'mod_workshop'), array('class' => 'gradetype')) .
 845                html_writer::tag('div', $grades->assessmentgrade->str_long_grade, array('class' => 'gradevalue')),
 846                array('class' => $cssclass)
 847            );
 848        }
 849
 850        $out .= html_writer::end_tag('div');
 851
 852        return $out;
 853    }
 854
 855    ////////////////////////////////////////////////////////////////////////////
 856    // Internal rendering helper methods
 857    ////////////////////////////////////////////////////////////////////////////
 858
 859    /**
 860     * Renders a list of files attached to the submission
 861     *
 862     * If format==html, then format a html string. If format==text, then format a text-only string.
 863     * Otherwise, returns html for non-images and html to display the image inline.
 864     *
 865     * @param int $submissionid submission identifier
 866     * @param string format the format of the returned string - html|text
 867     * @return string formatted text to be echoed
 868     */
 869    protected function helper_submission_attachments($submissionid, $format = 'html') {
 870        global $CFG;
 871        require_once($CFG->libdir.'/filelib.php');
 872
 873        $fs     = get_file_storage();
 874        $ctx    = $this->page->context;
 875        $files  = $fs->get_area_files($ctx->id, 'mod_workshop', 'submission_attachment', $submissionid);
 876
 877        $outputimgs     = '';   // images to be displayed inline
 878        $outputfiles    = '';   // list of attachment files
 879
 880        foreach ($files as $file) {
 881            if ($file->is_directory()) {
 882                continue;
 883            }
 884
 885            $filepath   = $file->get_filepath();
 886            $filename   = $file->get_filename();
 887            $fileurl    = moodle_url::make_pluginfile_url($ctx->id, 'mod_workshop', 'submission_attachment',
 888                            $submissionid, $filepath, $filename, true);
 889            $embedurl   = moodle_url::make_pluginfile_url($ctx->id, 'mod_workshop', 'submission_attachment',
 890                            $submissionid, $filepath, $filename, false);
 891            $embedurl   = new moodle_url($embedurl, array('preview' => 'bigthumb'));
 892            $type       = $file->get_mimetype();
 893            $image      = $this->output->pix_icon(file_file_icon($file), get_mimetype_description($file), 'moodle', array('class' => 'icon'));
 894
 895            $linkhtml   = html_writer::link($fileurl, $image . substr($filepath, 1) . $filename);
 896            $linktxt    = "$filename [$fileurl]";
 897
 898            if ($format == 'html') {
 899                if (file_mimetype_in_typegroup($type, 'web_image')) {
 900                    $preview     = html_writer::empty_tag('img', array('src' => $embedurl, 'alt' => '', 'class' => 'preview'));
 901                    $preview     = html_writer::tag('a', $preview, array('href' => $fileurl));
 902                    $outputimgs .= $this->output->container($preview);
 903
 904                } else {
 905                    $outputfiles .= html_writer::tag('li', $linkhtml, array('class' => $type));
 906                }
 907
 908            } else if ($format == 'text') {
 909                $outputfiles .= $linktxt . PHP_EOL;
 910            }
 911
 912            if (!empty($CFG->enableplagiarism)) {
 913                require_once($CFG->libdir.'/plagiarismlib.php');
 914                $outputfiles .= plagiarism_get_links(array('userid' => $file->get_userid(),
 915                    'file' => $file,
 916                    'cmid' => $this->page->cm->id,
 917                    'course' => $this->page->course->id));
 918            }
 919        }
 920
 921        if ($format == 'html') {
 922            if ($outputimgs) {
 923                $outputimgs = $this->output->container($outputimgs, 'images');
 924            }
 925
 926            if ($outputfiles) {
 927                $outputfiles = html_writer::tag('ul', $outputfiles, array('class' => 'files'));
 928            }
 929
 930            return $this->output->container($outputimgs . $outputfiles, 'attachments');
 931
 932        } else {
 933            return $outputfiles;
 934        }
 935    }
 936
 937    /**
 938     * Renders the tasks for the single phase in the user plan
 939     *
 940     * @param stdClass $tasks
 941     * @return string html code
 942     */
 943    protected function helper_user_plan_tasks(array $tasks) {
 944        $out = '';
 945        foreach ($tasks as $taskcode => $task) {
 946            $classes = '';
 947            $accessibilitytext = '';
 948            $icon = null;
 949            if ($task->completed === true) {
 950                $classes .= ' completed';
 951                $accessibilitytext .= get_string('taskdone', 'workshop') . ' ';
 952            } else if ($task->completed === false) {
 953                $classes .= ' fail';
 954                $accessibilitytext .= get_string('taskfail', 'workshop') . ' ';
 955            } else if ($task->completed === 'info') {
 956                $classes .= ' info';
 957                $accessibilitytext .= get_string('taskinfo', 'workshop') . ' ';
 958            } else {
 959                $accessibilitytext .= get_string('tasktodo', 'workshop') . ' ';
 960            }
 961            if (is_null($task->link)) {
 962                $title = html_writer::tag('span', $accessibilitytext, array('class' => 'accesshide'));
 963                $title .= $task->title;
 964            } else {
 965                $title = html_writer::tag('span', $accessibilitytext, array('class' => 'accesshide'));
 966                $title .= html_writer::link($task->link, $task->title);
 967            }
 968            $title = $this->output->container($title, 'title');
 969            $details = $this->output->container($task->details, 'details');
 970            $out .= html_writer::tag('li', $title . $details, array('class' => $classes));
 971        }
 972        if ($out) {
 973            $out = html_writer::tag('ul', $out, array('class' => 'tasks'));
 974        }
 975        return $out;
 976    }
 977
 978    /**
 979     * Renders a text with icons to sort by the given column
 980     *
 981     * This is intended for table headings.
 982     *
 983     * @param string $text    The heading text
 984     * @param string $sortid  The column id used for sorting
 985     * @param string $sortby  Currently sorted by (column id)
 986     * @param string $sorthow Currently sorted how (ASC|DESC)
 987     *
 988     * @return string
 989     */
 990    protected function helper_sortable_heading($text, $sortid=null, $sortby=null, $sorthow=null) {
 991
 992        $out = html_writer::tag('span', $text, array('class'=>'text'));
 993
 994        if (!is_null($sortid)) {
 995            if ($sortby !== $sortid or $sorthow !== 'ASC') {
 996                $url = new moodle_url($this->page->url);
 997                $url->params(array('sortby' => $sortid, 'sorthow' => 'ASC'));
 998                $out .= $this->output->action_icon($url, new pix_icon('t/sort_asc', get_string('sortasc', 'workshop')),
 999                    null, array('class' => 'iconsort sort asc'));
1000            }
1001            if ($sortby !== $sortid or $sorthow !== 'DESC') {
1002                $url = new moodle_url($this->page->url);
1003                $url->params(array('sortby' => $sortid, 'sorthow' => 'DESC'));
1004                $out .= $this->output->action_icon($url, new pix_icon('t/sort_desc', get_string('sortdesc', 'workshop')),
1005                    null, array('class' => 'iconsort sort desc'));
1006            }
1007        }
1008        return $out;
1009}
1010
1011    /**
1012     * @param stdClass $participant
1013     * @param array $userinfo
1014     * @return string
1015     */
1016    protected function helper_grading_report_participant(stdclass $participant, array $userinfo) {
1017        $userid = $participant->userid;
1018        $out  = $this->output->user_picture($userinfo[$userid], array('courseid' => $this->page->course->id, 'size' => 35));
1019        $out .= html_writer::tag('span', fullname($userinfo[$userid]));
1020
1021        return $out;
1022    }
1023
1024    /**
1025     * @param stdClass $participant
1026     * @return string
1027     */
1028    protected function helper_grading_report_submission(stdclass $participant) {
1029        global $CFG;
1030
1031        if (is_null($participant->submissionid)) {
1032            $out = $this->output->container(get_string('nosubmissionfound', 'workshop'), 'info');
1033        } else {
1034            $url = new moodle_url('/mod/workshop/submission.php',
1035                                  array('cmid' => $this->page->context->instanceid, 'id' => $participant->submissionid));
1036            $out = html_writer::link($url, format_string($participant->submissiontitle), array('class'=>'title'));
1037
1038            $lastmodified = get_string('userdatemodified', 'workshop', userdate($participant->submissionmodified));
1039            $out .= html_writer::tag('div', $lastmodified, array('class' => 'lastmodified'));
1040        }
1041
1042        return $out;
1043    }
1044
1045    /**
1046     * @todo Highlight the nulls
1047     * @param stdClass|null $assessment
1048     * @param bool $shownames
1049     * @param string $separator between the grade and the reviewer/author
1050     * @return string
1051     */
1052    protected function helper_grading_report_assessment($assessment, $shownames, array $userinfo, $separator) {
1053        global $CFG;
1054
1055        if (is_null($assessment)) {
1056            return get_string('nullgrade', 'workshop');
1057        }
1058        $a = new stdclass();
1059        $a->grade = is_null($assessment->grade) ? get_string('nullgrade', 'workshop') : $assessment->grade;
1060        $a->gradinggrade = is_null($assessment->gradinggrade) ? get_string('nullgrade', 'workshop') : $assessment->gradinggrade;
1061        $a->weight = $assessment->weight;
1062        // grrr the following logic should really be handled by a future language pack feature
1063        if (is_null($assessment->gradinggradeover)) {
1064            if ($a->weight == 1) {
1065                $grade = get_string('formatpeergrade', 'workshop', $a);
1066            } else {
1067                $grade = get_string('formatpeergradeweighted', 'workshop', $a);
1068            }
1069        } else {
1070            $a->gradinggradeover = $assessment->gradinggradeover;
1071            if ($a->weight == 1) {
1072                $grade = get_string('formatpeergradeover', 'workshop', $a);
1073            } else {
1074                $grade = get_string('formatpeergradeoverweighted', 'workshop', $a);
1075            }
1076        }
1077        $url = new moodle_url('/mod/workshop/assessment.php',
1078                              array('asid' => $assessment->assessmentid));
1079        $grade = html_writer::link($url, $grade, array('class'=>'grade'));
1080
1081        if ($shownames) {
1082            $userid = $assessment->userid;
1083            $name   = $this->output->user_picture($userinfo[$userid], array('courseid' => $this->page->course->id, 'size' => 16));
1084            $name  .= html_writer::tag('span', fullname($userinfo[$userid]), array('class' => 'fullname'));
1085            $name   = $separator . html_writer::tag('span', $name, array('class' => 'user'));
1086        } else {
1087            $name   = '';
1088        }
1089
1090        return $this->output->container($grade . $name, 'assessmentdetails');
1091    }
1092
1093    /**
1094     * Formats the aggreagated grades
1095     */
1096    protected function helper_grading_report_grade($grade, $over=null) {
1097        $a = new stdclass();
1098        $a->grade = is_null($grade) ? get_string('nullgrade', 'workshop') : $grade;
1099        if (is_null($over)) {
1100            $text = get_string('formataggregatedgrade', 'workshop', $a);
1101        } else {
1102            $a->over = is_null($over) ? get_string('nullgrade', 'workshop') : $over;
1103            $text = get_string('formataggregatedgradeover', 'workshop', $a);
1104        }
1105        return $text;
1106    }
1107
1108    ////////////////////////////////////////////////////////////////////////////
1109    // Static helpers
1110    ////////////////////////////////////////////////////////////////////////////
1111
1112    /**
1113     * Helper method dealing with the fact we can not just fetch the output of moodleforms
1114     *
1115     * @param moodleform $mform
1116     * @return string HTML
1117     */
1118    protected static function moodleform(moodleform $mform) {
1119
1120        ob_start();
1121        $mform->display();
1122        $o = ob_get_contents();
1123        ob_end_clean();
1124
1125        return $o;
1126    }
1127
1128    /**
1129     * Helper function returning the n-th item of the array
1130     *
1131     * @param array $a
1132     * @param int   $n from 0 to m, where m is th number of items in the array
1133     * @return mixed the $n-th element of $a
1134     */
1135    protected static function array_nth(array $a, $n) {
1136        $keys = array_keys($a);
1137        if ($n < 0 or $n > count($keys) - 1) {
1138            return null;
1139        }
1140        $key = $keys[$n];
1141        return $a[$key];
1142    }
1143
1144    /**
1145     * Tries to guess the fullname format set at the site
1146     *
1147     * @return string fl|lf
1148     */
1149    protected static function fullname_format() {
1150        $fake = new stdclass(); // fake user
1151        $fake->lastname = 'LLLL';
1152        $fake->firstname = 'FFFF';
1153        $fullname = get_string('fullnamedisplay', '', $fake);
1154        if (strpos($fullname, 'LLLL') < strpos($fullname, 'FFFF')) {
1155            return 'lf';
1156        } else {
1157            return 'fl';
1158        }
1159    }
1160}