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