Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 3.9.x will end* 10 May 2021 (12 months).
  • Bug fixes for security issues in 3.9.x will end* 8 May 2023 (36 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 and 403]

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  /**
  18   * This file contains a renderer for the assignment class
  19   *
  20   * @package   mod_assign
  21   * @copyright 2012 NetSpot {@link http://www.netspot.com.au}
  22   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  defined('MOODLE_INTERNAL') || die();
  26  
  27  require_once($CFG->dirroot . '/mod/assign/locallib.php');
  28  
  29  use \mod_assign\output\grading_app;
  30  
  31  /**
  32   * A custom renderer class that extends the plugin_renderer_base and is used by the assign module.
  33   *
  34   * @package mod_assign
  35   * @copyright 2012 NetSpot {@link http://www.netspot.com.au}
  36   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  37   */
  38  class mod_assign_renderer extends plugin_renderer_base {
  39  
  40      /**
  41       * Rendering assignment files
  42       *
  43       * @param context $context
  44       * @param int $userid
  45       * @param string $filearea
  46       * @param string $component
  47       * @return string
  48       */
  49      public function assign_files(context $context, $userid, $filearea, $component) {
  50          return $this->render(new assign_files($context, $userid, $filearea, $component));
  51      }
  52  
  53      /**
  54       * Rendering assignment files
  55       *
  56       * @param assign_files $tree
  57       * @return string
  58       */
  59      public function render_assign_files(assign_files $tree) {
  60          $this->htmlid = html_writer::random_id('assign_files_tree');
  61          $this->page->requires->js_init_call('M.mod_assign.init_tree', array(true, $this->htmlid));
  62          $html = '<div id="'.$this->htmlid.'">';
  63          $html .= $this->htmllize_tree($tree, $tree->dir);
  64          $html .= '</div>';
  65  
  66          if ($tree->portfolioform) {
  67              $html .= $tree->portfolioform;
  68          }
  69          return $html;
  70      }
  71  
  72      /**
  73       * Utility function to add a row of data to a table with 2 columns where the first column is the table's header.
  74       * Modified the table param and does not return a value.
  75       *
  76       * @param html_table $table The table to append the row of data to
  77       * @param string $first The first column text
  78       * @param string $second The second column text
  79       * @param array $firstattributes The first column attributes (optional)
  80       * @param array $secondattributes The second column attributes (optional)
  81       * @return void
  82       */
  83      private function add_table_row_tuple(html_table $table, $first, $second, $firstattributes = [],
  84              $secondattributes = []) {
  85          $row = new html_table_row();
  86          $cell1 = new html_table_cell($first);
  87          $cell1->header = true;
  88          if (!empty($firstattributes)) {
  89              $cell1->attributes = $firstattributes;
  90          }
  91          $cell2 = new html_table_cell($second);
  92          if (!empty($secondattributes)) {
  93              $cell2->attributes = $secondattributes;
  94          }
  95          $row->cells = array($cell1, $cell2);
  96          $table->data[] = $row;
  97      }
  98  
  99      /**
 100       * Render a grading message notification
 101       * @param assign_gradingmessage $result The result to render
 102       * @return string
 103       */
 104      public function render_assign_gradingmessage(assign_gradingmessage $result) {
 105          $urlparams = array('id' => $result->coursemoduleid, 'action'=>'grading');
 106          if (!empty($result->page)) {
 107              $urlparams['page'] = $result->page;
 108          }
 109          $url = new moodle_url('/mod/assign/view.php', $urlparams);
 110          $classes = $result->gradingerror ? 'notifyproblem' : 'notifysuccess';
 111  
 112          $o = '';
 113          $o .= $this->output->heading($result->heading, 4);
 114          $o .= $this->output->notification($result->message, $classes);
 115          $o .= $this->output->continue_button($url);
 116          return $o;
 117      }
 118  
 119      /**
 120       * Render the generic form
 121       * @param assign_form $form The form to render
 122       * @return string
 123       */
 124      public function render_assign_form(assign_form $form) {
 125          $o = '';
 126          if ($form->jsinitfunction) {
 127              $this->page->requires->js_init_call($form->jsinitfunction, array());
 128          }
 129          $o .= $this->output->box_start('boxaligncenter ' . $form->classname);
 130          $o .= $this->moodleform($form->form);
 131          $o .= $this->output->box_end();
 132          return $o;
 133      }
 134  
 135      /**
 136       * Render the user summary
 137       *
 138       * @param assign_user_summary $summary The user summary to render
 139       * @return string
 140       */
 141      public function render_assign_user_summary(assign_user_summary $summary) {
 142          $o = '';
 143          $supendedclass = '';
 144          $suspendedicon = '';
 145  
 146          if (!$summary->user) {
 147              return;
 148          }
 149  
 150          if ($summary->suspendeduser) {
 151              $supendedclass = ' usersuspended';
 152              $suspendedstring = get_string('userenrolmentsuspended', 'grades');
 153              $suspendedicon = ' ' . $this->pix_icon('i/enrolmentsuspended', $suspendedstring);
 154          }
 155          $o .= $this->output->container_start('usersummary');
 156          $o .= $this->output->box_start('boxaligncenter usersummarysection'.$supendedclass);
 157          if ($summary->blindmarking) {
 158              $o .= get_string('hiddenuser', 'assign') . $summary->uniqueidforuser.$suspendedicon;
 159          } else {
 160              $o .= $this->output->user_picture($summary->user);
 161              $o .= $this->output->spacer(array('width'=>30));
 162              $urlparams = array('id' => $summary->user->id, 'course'=>$summary->courseid);
 163              $url = new moodle_url('/user/view.php', $urlparams);
 164              $fullname = fullname($summary->user, $summary->viewfullnames);
 165              $extrainfo = array();
 166              foreach ($summary->extrauserfields as $extrafield) {
 167                  $extrainfo[] = s($summary->user->$extrafield);
 168              }
 169              if (count($extrainfo)) {
 170                  $fullname .= ' (' . implode(', ', $extrainfo) . ')';
 171              }
 172              $fullname .= $suspendedicon;
 173              $o .= $this->output->action_link($url, $fullname);
 174          }
 175          $o .= $this->output->box_end();
 176          $o .= $this->output->container_end();
 177  
 178          return $o;
 179      }
 180  
 181      /**
 182       * Render the submit for grading page
 183       *
 184       * @param assign_submit_for_grading_page $page
 185       * @return string
 186       */
 187      public function render_assign_submit_for_grading_page($page) {
 188          $o = '';
 189  
 190          $o .= $this->output->container_start('submitforgrading');
 191          $o .= $this->output->heading(get_string('confirmsubmissionheading', 'assign'), 3);
 192  
 193          $cancelurl = new moodle_url('/mod/assign/view.php', array('id' => $page->coursemoduleid));
 194          if (count($page->notifications)) {
 195              // At least one of the submission plugins is not ready for submission.
 196  
 197              $o .= $this->output->heading(get_string('submissionnotready', 'assign'), 4);
 198  
 199              foreach ($page->notifications as $notification) {
 200                  $o .= $this->output->notification($notification);
 201              }
 202  
 203              $o .= $this->output->continue_button($cancelurl);
 204          } else {
 205              // All submission plugins ready - show the confirmation form.
 206              $o .= $this->moodleform($page->confirmform);
 207          }
 208          $o .= $this->output->container_end();
 209  
 210          return $o;
 211      }
 212  
 213      /**
 214       * Page is done - render the footer.
 215       *
 216       * @return void
 217       */
 218      public function render_footer() {
 219          return $this->output->footer();
 220      }
 221  
 222      /**
 223       * Render the header.
 224       *
 225       * @param assign_header $header
 226       * @return string
 227       */
 228      public function render_assign_header(assign_header $header) {
 229          $o = '';
 230  
 231          if ($header->subpage) {
 232              $this->page->navbar->add($header->subpage);
 233              $args = ['contextname' => $header->context->get_context_name(false, true), 'subpage' => $header->subpage];
 234              $title = get_string('subpagetitle', 'assign', $args);
 235          } else {
 236              $title = $header->context->get_context_name(false, true);
 237          }
 238          $courseshortname = $header->context->get_course_context()->get_context_name(false, true);
 239          $title = $courseshortname . ': ' . $title;
 240          $heading = format_string($header->assign->name, false, array('context' => $header->context));
 241  
 242          $this->page->set_title($title);
 243          $this->page->set_heading($this->page->course->fullname);
 244  
 245          $o .= $this->output->header();
 246          $o .= $this->output->heading($heading);
 247          if ($header->preface) {
 248              $o .= $header->preface;
 249          }
 250  
 251          if ($header->showintro) {
 252              $o .= $this->output->box_start('generalbox boxaligncenter', 'intro');
 253              $o .= format_module_intro('assign', $header->assign, $header->coursemoduleid);
 254              $o .= $header->postfix;
 255              $o .= $this->output->box_end();
 256          }
 257  
 258          return $o;
 259      }
 260  
 261      /**
 262       * Render the header for an individual plugin.
 263       *
 264       * @param assign_plugin_header $header
 265       * @return string
 266       */
 267      public function render_assign_plugin_header(assign_plugin_header $header) {
 268          $o = $header->plugin->view_header();
 269          return $o;
 270      }
 271  
 272      /**
 273       * Render a table containing the current status of the grading process.
 274       *
 275       * @param assign_grading_summary $summary
 276       * @return string
 277       */
 278      public function render_assign_grading_summary(assign_grading_summary $summary) {
 279          // Create a table for the data.
 280          $o = '';
 281          $o .= $this->output->container_start('gradingsummary');
 282          $o .= $this->output->heading(get_string('gradingsummary', 'assign'), 3);
 283          $o .= $this->output->box_start('boxaligncenter gradingsummarytable');
 284          $t = new html_table();
 285  
 286          // Visibility Status.
 287          $cell1content = get_string('hiddenfromstudents');
 288          $cell2content = (!$summary->isvisible) ? get_string('yes') : get_string('no');
 289          $this->add_table_row_tuple($t, $cell1content, $cell2content);
 290  
 291          // Status.
 292          if ($summary->teamsubmission) {
 293              if ($summary->warnofungroupedusers === assign_grading_summary::WARN_GROUPS_REQUIRED) {
 294                  $o .= $this->output->notification(get_string('ungroupedusers', 'assign'));
 295              } else if ($summary->warnofungroupedusers === assign_grading_summary::WARN_GROUPS_OPTIONAL) {
 296                  $o .= $this->output->notification(get_string('ungroupedusersoptional', 'assign'));
 297              }
 298              $cell1content = get_string('numberofteams', 'assign');
 299          } else {
 300              $cell1content = get_string('numberofparticipants', 'assign');
 301          }
 302  
 303          $cell2content = $summary->participantcount;
 304          $this->add_table_row_tuple($t, $cell1content, $cell2content);
 305  
 306          // Drafts count and dont show drafts count when using offline assignment.
 307          if ($summary->submissiondraftsenabled && $summary->submissionsenabled) {
 308              $cell1content = get_string('numberofdraftsubmissions', 'assign');
 309              $cell2content = $summary->submissiondraftscount;
 310              $this->add_table_row_tuple($t, $cell1content, $cell2content);
 311          }
 312  
 313          // Submitted for grading.
 314          if ($summary->submissionsenabled) {
 315              $cell1content = get_string('numberofsubmittedassignments', 'assign');
 316              $cell2content = $summary->submissionssubmittedcount;
 317              $this->add_table_row_tuple($t, $cell1content, $cell2content);
 318  
 319              if (!$summary->teamsubmission) {
 320                  $cell1content = get_string('numberofsubmissionsneedgrading', 'assign');
 321                  $cell2content = $summary->submissionsneedgradingcount;
 322                  $this->add_table_row_tuple($t, $cell1content, $cell2content);
 323              }
 324          }
 325  
 326          $time = time();
 327          if ($summary->duedate) {
 328              // Due date.
 329              $cell1content = get_string('duedate', 'assign');
 330              $duedate = $summary->duedate;
 331              if ($summary->courserelativedatesmode) {
 332                  // Returns a formatted string, in the format '10d 10h 45m'.
 333                  $diffstr = get_time_interval_string($duedate, $summary->coursestartdate);
 334                  if ($duedate >= $summary->coursestartdate) {
 335                      $cell2content = get_string('relativedatessubmissionduedateafter', 'mod_assign',
 336                          ['datediffstr' => $diffstr]);
 337                  } else {
 338                      $cell2content = get_string('relativedatessubmissionduedatebefore', 'mod_assign',
 339                          ['datediffstr' => $diffstr]);
 340                  }
 341              } else {
 342                  $cell2content = userdate($duedate);
 343              }
 344  
 345              $this->add_table_row_tuple($t, $cell1content, $cell2content);
 346  
 347              // Time remaining.
 348              $cell1content = get_string('timeremaining', 'assign');
 349              if ($summary->courserelativedatesmode) {
 350                  $cell2content = get_string('relativedatessubmissiontimeleft', 'mod_assign');
 351              } else {
 352                  if ($duedate - $time <= 0) {
 353                      $cell2content = get_string('assignmentisdue', 'assign');
 354                  } else {
 355                      $cell2content = format_time($duedate - $time);
 356                  }
 357              }
 358  
 359              $this->add_table_row_tuple($t, $cell1content, $cell2content);
 360  
 361              if ($duedate < $time) {
 362                  $cell1content = get_string('latesubmissions', 'assign');
 363                  $cutoffdate = $summary->cutoffdate;
 364                  if ($cutoffdate) {
 365                      if ($cutoffdate > $time) {
 366                          $cell2content = get_string('latesubmissionsaccepted', 'assign', userdate($summary->cutoffdate));
 367                      } else {
 368                          $cell2content = get_string('nomoresubmissionsaccepted', 'assign');
 369                      }
 370  
 371                      $this->add_table_row_tuple($t, $cell1content, $cell2content);
 372                  }
 373              }
 374  
 375          }
 376  
 377          // All done - write the table.
 378          $o .= html_writer::table($t);
 379          $o .= $this->output->box_end();
 380  
 381          // Link to the grading page.
 382          $o .= html_writer::start_tag('center');
 383          $o .= $this->output->container_start('submissionlinks');
 384          $urlparams = array('id' => $summary->coursemoduleid, 'action' => 'grading');
 385          $url = new moodle_url('/mod/assign/view.php', $urlparams);
 386          $o .= html_writer::link($url, get_string('viewgrading', 'mod_assign'),
 387              ['class' => 'btn btn-secondary']);
 388          if ($summary->cangrade) {
 389              $urlparams = array('id' => $summary->coursemoduleid, 'action' => 'grader');
 390              $url = new moodle_url('/mod/assign/view.php', $urlparams);
 391              $o .= html_writer::link($url, get_string('grade'),
 392                  ['class' => 'btn btn-primary ml-1']);
 393          }
 394          $o .= $this->output->container_end();
 395  
 396          // Close the container and insert a spacer.
 397          $o .= $this->output->container_end();
 398          $o .= html_writer::end_tag('center');
 399  
 400          return $o;
 401      }
 402  
 403      /**
 404       * Render a table containing all the current grades and feedback.
 405       *
 406       * @param assign_feedback_status $status
 407       * @return string
 408       */
 409      public function render_assign_feedback_status(assign_feedback_status $status) {
 410          $o = '';
 411  
 412          $o .= $this->output->container_start('feedback');
 413          $o .= $this->output->heading(get_string('feedback', 'assign'), 3);
 414          $o .= $this->output->box_start('boxaligncenter feedbacktable');
 415          $t = new html_table();
 416  
 417          // Grade.
 418          if (isset($status->gradefordisplay)) {
 419              $cell1content = get_string('grade');
 420              $cell2content = $status->gradefordisplay;
 421              $this->add_table_row_tuple($t, $cell1content, $cell2content);
 422  
 423              // Grade date.
 424              $cell1content = get_string('gradedon', 'assign');
 425              $cell2content = userdate($status->gradeddate);
 426              $this->add_table_row_tuple($t, $cell1content, $cell2content);
 427          }
 428  
 429          if ($status->grader) {
 430              // Grader.
 431              $cell1content = get_string('gradedby', 'assign');
 432              $cell2content = $this->output->user_picture($status->grader) .
 433                              $this->output->spacer(array('width' => 30)) .
 434                              fullname($status->grader, $status->canviewfullnames);
 435              $this->add_table_row_tuple($t, $cell1content, $cell2content);
 436          }
 437  
 438          foreach ($status->feedbackplugins as $plugin) {
 439              if ($plugin->is_enabled() &&
 440                      $plugin->is_visible() &&
 441                      $plugin->has_user_summary() &&
 442                      !empty($status->grade) &&
 443                      !$plugin->is_empty($status->grade)) {
 444  
 445                  $displaymode = assign_feedback_plugin_feedback::SUMMARY;
 446                  $pluginfeedback = new assign_feedback_plugin_feedback($plugin,
 447                                                                        $status->grade,
 448                                                                        $displaymode,
 449                                                                        $status->coursemoduleid,
 450                                                                        $status->returnaction,
 451                                                                        $status->returnparams);
 452                  $cell1content = $plugin->get_name();
 453                  $cell2content = $this->render($pluginfeedback);
 454                  $this->add_table_row_tuple($t, $cell1content, $cell2content);
 455              }
 456          }
 457  
 458          $o .= html_writer::table($t);
 459          $o .= $this->output->box_end();
 460  
 461          $o .= $this->output->container_end();
 462          return $o;
 463      }
 464  
 465      /**
 466       * Render a compact view of the current status of the submission.
 467       *
 468       * @param assign_submission_status_compact $status
 469       * @return string
 470       */
 471      public function render_assign_submission_status_compact(assign_submission_status_compact $status) {
 472          $o = '';
 473          $o .= $this->output->container_start('submissionstatustable');
 474          $o .= $this->output->heading(get_string('submission', 'assign'), 3);
 475          $time = time();
 476  
 477          if ($status->teamsubmissionenabled) {
 478              $group = $status->submissiongroup;
 479              if ($group) {
 480                  $team = format_string($group->name, false, $status->context);
 481              } else if ($status->preventsubmissionnotingroup) {
 482                  if (count($status->usergroups) == 0) {
 483                      $team = '<span class="alert alert-error">' . get_string('noteam', 'assign') . '</span>';
 484                  } else if (count($status->usergroups) > 1) {
 485                      $team = '<span class="alert alert-error">' . get_string('multipleteams', 'assign') . '</span>';
 486                  }
 487              } else {
 488                  $team = get_string('defaultteam', 'assign');
 489              }
 490              $o .= $this->output->container(get_string('teamname', 'assign', $team), 'teamname');
 491          }
 492  
 493          if (!$status->teamsubmissionenabled) {
 494              if ($status->submission && $status->submission->status != ASSIGN_SUBMISSION_STATUS_NEW) {
 495                  $statusstr = get_string('submissionstatus_' . $status->submission->status, 'assign');
 496                  $o .= $this->output->container($statusstr, 'submissionstatus' . $status->submission->status);
 497              } else {
 498                  if (!$status->submissionsenabled) {
 499                      $o .= $this->output->container(get_string('noonlinesubmissions', 'assign'), 'submissionstatus');
 500                  } else {
 501                      $o .= $this->output->container(get_string('noattempt', 'assign'), 'submissionstatus');
 502                  }
 503              }
 504          } else {
 505              $group = $status->submissiongroup;
 506              if (!$group && $status->preventsubmissionnotingroup) {
 507                  $o .= $this->output->container(get_string('nosubmission', 'assign'), 'submissionstatus');
 508              } else if ($status->teamsubmission && $status->teamsubmission->status != ASSIGN_SUBMISSION_STATUS_NEW) {
 509                  $teamstatus = $status->teamsubmission->status;
 510                  $submissionsummary = get_string('submissionstatus_' . $teamstatus, 'assign');
 511                  $groupid = 0;
 512                  if ($status->submissiongroup) {
 513                      $groupid = $status->submissiongroup->id;
 514                  }
 515  
 516                  $members = $status->submissiongroupmemberswhoneedtosubmit;
 517                  $userslist = array();
 518                  foreach ($members as $member) {
 519                      $urlparams = array('id' => $member->id, 'course' => $status->courseid);
 520                      $url = new moodle_url('/user/view.php', $urlparams);
 521                      if ($status->view == assign_submission_status::GRADER_VIEW && $status->blindmarking) {
 522                          $userslist[] = $member->alias;
 523                      } else {
 524                          $fullname = fullname($member, $status->canviewfullnames);
 525                          $userslist[] = $this->output->action_link($url, $fullname);
 526                      }
 527                  }
 528                  if (count($userslist) > 0) {
 529                      $userstr = join(', ', $userslist);
 530                      $formatteduserstr = get_string('userswhoneedtosubmit', 'assign', $userstr);
 531                      $submissionsummary .= $this->output->container($formatteduserstr);
 532                  }
 533                  $o .= $this->output->container($submissionsummary, 'submissionstatus' . $status->teamsubmission->status);
 534              } else {
 535                  if (!$status->submissionsenabled) {
 536                      $o .= $this->output->container(get_string('noonlinesubmissions', 'assign'), 'submissionstatus');
 537                  } else {
 538                      $o .= $this->output->container(get_string('nosubmission', 'assign'), 'submissionstatus');
 539                  }
 540              }
 541          }
 542  
 543          // Is locked?
 544          if ($status->locked) {
 545              $o .= $this->output->container(get_string('submissionslocked', 'assign'), 'submissionlocked');
 546          }
 547  
 548          // Grading status.
 549          $statusstr = '';
 550          $classname = 'gradingstatus';
 551          if ($status->gradingstatus == ASSIGN_GRADING_STATUS_GRADED ||
 552              $status->gradingstatus == ASSIGN_GRADING_STATUS_NOT_GRADED) {
 553              $statusstr = get_string($status->gradingstatus, 'assign');
 554          } else {
 555              $gradingstatus = 'markingworkflowstate' . $status->gradingstatus;
 556              $statusstr = get_string($gradingstatus, 'assign');
 557          }
 558          if ($status->gradingstatus == ASSIGN_GRADING_STATUS_GRADED ||
 559              $status->gradingstatus == ASSIGN_MARKING_WORKFLOW_STATE_RELEASED) {
 560              $classname = 'submissiongraded';
 561          } else {
 562              $classname = 'submissionnotgraded';
 563          }
 564          $o .= $this->output->container($statusstr, $classname);
 565  
 566          $submission = $status->teamsubmission ? $status->teamsubmission : $status->submission;
 567          $duedate = $status->duedate;
 568          if ($duedate > 0) {
 569  
 570              if ($status->extensionduedate) {
 571                  // Extension date.
 572                  $duedate = $status->extensionduedate;
 573              }
 574  
 575              // Time remaining.
 576              $classname = 'timeremaining';
 577              if ($duedate - $time <= 0) {
 578                  if (!$submission ||
 579                          $submission->status != ASSIGN_SUBMISSION_STATUS_SUBMITTED) {
 580                      if ($status->submissionsenabled) {
 581                          $remaining = get_string('overdue', 'assign', format_time($time - $duedate));
 582                          $classname = 'overdue';
 583                      } else {
 584                          $remaining = get_string('duedatereached', 'assign');
 585                      }
 586                  } else {
 587                      if ($submission->timemodified > $duedate) {
 588                          $remaining = get_string('submittedlate',
 589                                                'assign',
 590                                                format_time($submission->timemodified - $duedate));
 591                          $classname = 'latesubmission';
 592                      } else {
 593                          $remaining = get_string('submittedearly',
 594                                                 'assign',
 595                                                 format_time($submission->timemodified - $duedate));
 596                          $classname = 'earlysubmission';
 597                      }
 598                  }
 599              } else {
 600                  $remaining = get_string('paramtimeremaining', 'assign', format_time($duedate - $time));
 601              }
 602              $o .= $this->output->container($remaining, $classname);
 603          }
 604  
 605          // Show graders whether this submission is editable by students.
 606          if ($status->view == assign_submission_status::GRADER_VIEW) {
 607              if ($status->canedit) {
 608                  $o .= $this->output->container(get_string('submissioneditable', 'assign'), 'submissioneditable');
 609              } else {
 610                  $o .= $this->output->container(get_string('submissionnoteditable', 'assign'), 'submissionnoteditable');
 611              }
 612          }
 613  
 614          // Grading criteria preview.
 615          if (!empty($status->gradingcontrollerpreview)) {
 616              $o .= $this->output->container($status->gradingcontrollerpreview, 'gradingmethodpreview');
 617          }
 618  
 619          if ($submission) {
 620  
 621              if (!$status->teamsubmission || $status->submissiongroup != false || !$status->preventsubmissionnotingroup) {
 622                  foreach ($status->submissionplugins as $plugin) {
 623                      $pluginshowsummary = !$plugin->is_empty($submission) || !$plugin->allow_submissions();
 624                      if ($plugin->is_enabled() &&
 625                          $plugin->is_visible() &&
 626                          $plugin->has_user_summary() &&
 627                          $pluginshowsummary
 628                      ) {
 629  
 630                          $displaymode = assign_submission_plugin_submission::SUMMARY;
 631                          $pluginsubmission = new assign_submission_plugin_submission($plugin,
 632                              $submission,
 633                              $displaymode,
 634                              $status->coursemoduleid,
 635                              $status->returnaction,
 636                              $status->returnparams);
 637                          $plugincomponent = $plugin->get_subtype() . '_' . $plugin->get_type();
 638                          $o .= $this->output->container($this->render($pluginsubmission), 'assignsubmission ' . $plugincomponent);
 639                      }
 640                  }
 641              }
 642          }
 643  
 644          $o .= $this->output->container_end();
 645          return $o;
 646      }
 647  
 648      /**
 649       * Render a table containing the current status of the submission.
 650       *
 651       * @param assign_submission_status $status
 652       * @return string
 653       */
 654      public function render_assign_submission_status(assign_submission_status $status) {
 655          $o = '';
 656          $o .= $this->output->container_start('submissionstatustable');
 657          $o .= $this->output->heading(get_string('submissionstatusheading', 'assign'), 3);
 658          $time = time();
 659  
 660          if ($status->allowsubmissionsfromdate &&
 661                  $time <= $status->allowsubmissionsfromdate) {
 662              $o .= $this->output->box_start('generalbox boxaligncenter submissionsalloweddates');
 663              if ($status->alwaysshowdescription) {
 664                  $date = userdate($status->allowsubmissionsfromdate);
 665                  $o .= get_string('allowsubmissionsfromdatesummary', 'assign', $date);
 666              } else {
 667                  $date = userdate($status->allowsubmissionsfromdate);
 668                  $o .= get_string('allowsubmissionsanddescriptionfromdatesummary', 'assign', $date);
 669              }
 670              $o .= $this->output->box_end();
 671          }
 672          $o .= $this->output->box_start('boxaligncenter submissionsummarytable');
 673  
 674          $t = new html_table();
 675  
 676          $warningmsg = '';
 677          if ($status->teamsubmissionenabled) {
 678              $cell1content = get_string('submissionteam', 'assign');
 679              $group = $status->submissiongroup;
 680              if ($group) {
 681                  $cell2content = format_string($group->name, false, $status->context);
 682              } else if ($status->preventsubmissionnotingroup) {
 683                  if (count($status->usergroups) == 0) {
 684                      $notification = new \core\output\notification(get_string('noteam', 'assign'), 'error');
 685                      $notification->set_show_closebutton(false);
 686                      $warningmsg = $this->output->notification(get_string('noteam_desc', 'assign'), 'error');
 687                  } else if (count($status->usergroups) > 1) {
 688                      $notification = new \core\output\notification(get_string('multipleteams', 'assign'), 'error');
 689                      $notification->set_show_closebutton(false);
 690                      $warningmsg = $this->output->notification(get_string('multipleteams_desc', 'assign'), 'error');
 691                  }
 692                  $cell2content = $this->output->render($notification);
 693              } else {
 694                  $cell2content = get_string('defaultteam', 'assign');
 695              }
 696  
 697              $this->add_table_row_tuple($t, $cell1content, $cell2content);
 698          }
 699  
 700          if ($status->attemptreopenmethod != ASSIGN_ATTEMPT_REOPEN_METHOD_NONE) {
 701              $currentattempt = 1;
 702              if (!$status->teamsubmissionenabled) {
 703                  if ($status->submission) {
 704                      $currentattempt = $status->submission->attemptnumber + 1;
 705                  }
 706              } else {
 707                  if ($status->teamsubmission) {
 708                      $currentattempt = $status->teamsubmission->attemptnumber + 1;
 709                  }
 710              }
 711  
 712              $cell1content = get_string('attemptnumber', 'assign');
 713              $maxattempts = $status->maxattempts;
 714              if ($maxattempts == ASSIGN_UNLIMITED_ATTEMPTS) {
 715                  $cell2content = get_string('currentattempt', 'assign', $currentattempt);
 716              } else {
 717                  $cell2content = get_string('currentattemptof', 'assign',
 718                      array('attemptnumber' => $currentattempt, 'maxattempts' => $maxattempts));
 719              }
 720  
 721              $this->add_table_row_tuple($t, $cell1content, $cell2content);
 722          }
 723  
 724          $cell1content = get_string('submissionstatus', 'assign');
 725          $cell2attributes = [];
 726          if (!$status->teamsubmissionenabled) {
 727              if ($status->submission && $status->submission->status != ASSIGN_SUBMISSION_STATUS_NEW) {
 728                  $cell2content = get_string('submissionstatus_' . $status->submission->status, 'assign');
 729                  $cell2attributes = array('class' => 'submissionstatus' . $status->submission->status);
 730              } else {
 731                  if (!$status->submissionsenabled) {
 732                      $cell2content = get_string('noonlinesubmissions', 'assign');
 733                  } else {
 734                      $cell2content = get_string('noattempt', 'assign');
 735                  }
 736              }
 737          } else {
 738              $group = $status->submissiongroup;
 739              if (!$group && $status->preventsubmissionnotingroup) {
 740                  $cell2content = get_string('nosubmission', 'assign');
 741              } else if ($status->teamsubmission && $status->teamsubmission->status != ASSIGN_SUBMISSION_STATUS_NEW) {
 742                  $teamstatus = $status->teamsubmission->status;
 743                  $cell2content = get_string('submissionstatus_' . $teamstatus, 'assign');
 744  
 745                  $members = $status->submissiongroupmemberswhoneedtosubmit;
 746                  $userslist = array();
 747                  foreach ($members as $member) {
 748                      $urlparams = array('id' => $member->id, 'course'=>$status->courseid);
 749                      $url = new moodle_url('/user/view.php', $urlparams);
 750                      if ($status->view == assign_submission_status::GRADER_VIEW && $status->blindmarking) {
 751                          $userslist[] = $member->alias;
 752                      } else {
 753                          $fullname = fullname($member, $status->canviewfullnames);
 754                          $userslist[] = $this->output->action_link($url, $fullname);
 755                      }
 756                  }
 757                  if (count($userslist) > 0) {
 758                      $userstr = join(', ', $userslist);
 759                      $formatteduserstr = get_string('userswhoneedtosubmit', 'assign', $userstr);
 760                      $cell2content .= $this->output->container($formatteduserstr);
 761                  }
 762  
 763                  $cell2attributes = array('class' => 'submissionstatus' . $status->teamsubmission->status);
 764              } else {
 765                  if (!$status->submissionsenabled) {
 766                      $cell2content = get_string('noonlinesubmissions', 'assign');
 767                  } else {
 768                      $cell2content = get_string('nosubmission', 'assign');
 769                  }
 770              }
 771          }
 772  
 773          $this->add_table_row_tuple($t, $cell1content, $cell2content, [], $cell2attributes);
 774  
 775          // Is locked?
 776          if ($status->locked) {
 777              $cell1content = '';
 778              $cell2content = get_string('submissionslocked', 'assign');
 779              $cell2attributes = array('class' => 'submissionlocked');
 780              $this->add_table_row_tuple($t, $cell1content, $cell2content, [], $cell2attributes);
 781          }
 782  
 783          // Grading status.
 784          $cell1content = get_string('gradingstatus', 'assign');
 785          if ($status->gradingstatus == ASSIGN_GRADING_STATUS_GRADED ||
 786              $status->gradingstatus == ASSIGN_GRADING_STATUS_NOT_GRADED) {
 787              $cell2content = get_string($status->gradingstatus, 'assign');
 788          } else {
 789              $gradingstatus = 'markingworkflowstate' . $status->gradingstatus;
 790              $cell2content = get_string($gradingstatus, 'assign');
 791          }
 792          if ($status->gradingstatus == ASSIGN_GRADING_STATUS_GRADED ||
 793              $status->gradingstatus == ASSIGN_MARKING_WORKFLOW_STATE_RELEASED) {
 794              $cell2attributes = array('class' => 'submissiongraded');
 795          } else {
 796              $cell2attributes = array('class' => 'submissionnotgraded');
 797          }
 798          $this->add_table_row_tuple($t, $cell1content, $cell2content, [], $cell2attributes);
 799  
 800          $submission = $status->teamsubmission ? $status->teamsubmission : $status->submission;
 801          $duedate = $status->duedate;
 802          if ($duedate > 0) {
 803              // Due date.
 804              $cell1content = get_string('duedate', 'assign');
 805              $cell2content = userdate($duedate);
 806              $this->add_table_row_tuple($t, $cell1content, $cell2content);
 807  
 808              if ($status->view == assign_submission_status::GRADER_VIEW) {
 809                  if ($status->cutoffdate) {
 810                      // Cut off date.
 811                      $cell1content = get_string('cutoffdate', 'assign');
 812                      $cell2content = userdate($status->cutoffdate);
 813                      $this->add_table_row_tuple($t, $cell1content, $cell2content);
 814                  }
 815              }
 816  
 817              if ($status->extensionduedate) {
 818                  // Extension date.
 819                  $cell1content = get_string('extensionduedate', 'assign');
 820                  $cell2content = userdate($status->extensionduedate);
 821                  $this->add_table_row_tuple($t, $cell1content, $cell2content);
 822                  $duedate = $status->extensionduedate;
 823              }
 824  
 825              // Time remaining.
 826              $cell1content = get_string('timeremaining', 'assign');
 827              $cell2attributes = [];
 828              if ($duedate - $time <= 0) {
 829                  if (!$submission ||
 830                          $submission->status != ASSIGN_SUBMISSION_STATUS_SUBMITTED) {
 831                      if ($status->submissionsenabled) {
 832                          $cell2content = get_string('overdue', 'assign', format_time($time - $duedate));
 833                          $cell2attributes = array('class' => 'overdue');
 834                      } else {
 835                          $cell2content = get_string('duedatereached', 'assign');
 836                      }
 837                  } else {
 838                      if ($submission->timemodified > $duedate) {
 839                          $cell2content = get_string('submittedlate',
 840                                                'assign',
 841                                                format_time($submission->timemodified - $duedate));
 842                          $cell2attributes = array('class' => 'latesubmission');
 843                      } else {
 844                          $cell2content = get_string('submittedearly',
 845                                                 'assign',
 846                                                 format_time($submission->timemodified - $duedate));
 847                          $cell2attributes = array('class' => 'earlysubmission');
 848                      }
 849                  }
 850              } else {
 851                  $cell2content = format_time($duedate - $time);
 852              }
 853              $this->add_table_row_tuple($t, $cell1content, $cell2content, [], $cell2attributes);
 854          }
 855  
 856          // Show graders whether this submission is editable by students.
 857          if ($status->view == assign_submission_status::GRADER_VIEW) {
 858              $cell1content = get_string('editingstatus', 'assign');
 859              if ($status->canedit) {
 860                  $cell2content = get_string('submissioneditable', 'assign');
 861                  $cell2attributes = array('class' => 'submissioneditable');
 862              } else {
 863                  $cell2content = get_string('submissionnoteditable', 'assign');
 864                  $cell2attributes = array('class' => 'submissionnoteditable');
 865              }
 866              $this->add_table_row_tuple($t, $cell1content, $cell2content, [], $cell2attributes);
 867          }
 868  
 869          // Grading criteria preview.
 870          if (!empty($status->gradingcontrollerpreview)) {
 871              $cell1content = get_string('gradingmethodpreview', 'assign');
 872              $cell2content = $status->gradingcontrollerpreview;
 873              $this->add_table_row_tuple($t, $cell1content, $cell2content, [], $cell2attributes);
 874          }
 875  
 876          // Last modified.
 877          if ($submission) {
 878              $cell1content = get_string('timemodified', 'assign');
 879  
 880              if ($submission->status != ASSIGN_SUBMISSION_STATUS_NEW) {
 881                  $cell2content = userdate($submission->timemodified);
 882              } else {
 883                  $cell2content = "-";
 884              }
 885  
 886              $this->add_table_row_tuple($t, $cell1content, $cell2content);
 887  
 888              if (!$status->teamsubmission || $status->submissiongroup != false || !$status->preventsubmissionnotingroup) {
 889                  foreach ($status->submissionplugins as $plugin) {
 890                      $pluginshowsummary = !$plugin->is_empty($submission) || !$plugin->allow_submissions();
 891                      if ($plugin->is_enabled() &&
 892                          $plugin->is_visible() &&
 893                          $plugin->has_user_summary() &&
 894                          $pluginshowsummary
 895                      ) {
 896  
 897                          $cell1content = $plugin->get_name();
 898                          $displaymode = assign_submission_plugin_submission::SUMMARY;
 899                          $pluginsubmission = new assign_submission_plugin_submission($plugin,
 900                              $submission,
 901                              $displaymode,
 902                              $status->coursemoduleid,
 903                              $status->returnaction,
 904                              $status->returnparams);
 905                          $cell2content = $this->render($pluginsubmission);
 906                          $this->add_table_row_tuple($t, $cell1content, $cell2content);
 907                      }
 908                  }
 909              }
 910          }
 911  
 912          $o .= $warningmsg;
 913          $o .= html_writer::table($t);
 914          $o .= $this->output->box_end();
 915  
 916          // Links.
 917          if ($status->view == assign_submission_status::STUDENT_VIEW) {
 918              if ($status->canedit) {
 919                  if (!$submission || $submission->status == ASSIGN_SUBMISSION_STATUS_NEW) {
 920                      $o .= $this->output->box_start('generalbox submissionaction');
 921                      $urlparams = array('id' => $status->coursemoduleid, 'action' => 'editsubmission');
 922                      $o .= $this->output->single_button(new moodle_url('/mod/assign/view.php', $urlparams),
 923                                                         get_string('addsubmission', 'assign'), 'get');
 924                      $o .= $this->output->box_start('boxaligncenter submithelp');
 925                      $o .= get_string('addsubmission_help', 'assign');
 926                      $o .= $this->output->box_end();
 927                      $o .= $this->output->box_end();
 928                  } else if ($submission->status == ASSIGN_SUBMISSION_STATUS_REOPENED) {
 929                      $o .= $this->output->box_start('generalbox submissionaction');
 930                      $urlparams = array('id' => $status->coursemoduleid,
 931                                         'action' => 'editprevioussubmission',
 932                                         'sesskey'=>sesskey());
 933                      $o .= $this->output->single_button(new moodle_url('/mod/assign/view.php', $urlparams),
 934                                                         get_string('addnewattemptfromprevious', 'assign'), 'get');
 935                      $o .= $this->output->box_start('boxaligncenter submithelp');
 936                      $o .= get_string('addnewattemptfromprevious_help', 'assign');
 937                      $o .= $this->output->box_end();
 938                      $o .= $this->output->box_end();
 939                      $o .= $this->output->box_start('generalbox submissionaction');
 940                      $urlparams = array('id' => $status->coursemoduleid, 'action' => 'editsubmission');
 941                      $o .= $this->output->single_button(new moodle_url('/mod/assign/view.php', $urlparams),
 942                                                         get_string('addnewattempt', 'assign'), 'get');
 943                      $o .= $this->output->box_start('boxaligncenter submithelp');
 944                      $o .= get_string('addnewattempt_help', 'assign');
 945                      $o .= $this->output->box_end();
 946                      $o .= $this->output->box_end();
 947                  } else {
 948                      $o .= $this->output->box_start('generalbox submissionaction');
 949                      $urlparams = array('id' => $status->coursemoduleid, 'action' => 'editsubmission');
 950                      $o .= $this->output->single_button(new moodle_url('/mod/assign/view.php', $urlparams),
 951                                                         get_string('editsubmission', 'assign'), 'get');
 952                      $urlparams = array('id' => $status->coursemoduleid, 'action' => 'removesubmissionconfirm');
 953                      $o .= $this->output->single_button(new moodle_url('/mod/assign/view.php', $urlparams),
 954                                                         get_string('removesubmission', 'assign'), 'get');
 955                      $o .= $this->output->box_start('boxaligncenter submithelp');
 956                      $o .= get_string('editsubmission_help', 'assign');
 957                      $o .= $this->output->box_end();
 958                      $o .= $this->output->box_end();
 959                  }
 960              }
 961  
 962              if ($status->cansubmit) {
 963                  $urlparams = array('id' => $status->coursemoduleid, 'action'=>'submit');
 964                  $o .= $this->output->box_start('generalbox submissionaction');
 965                  $o .= $this->output->single_button(new moodle_url('/mod/assign/view.php', $urlparams),
 966                                                     get_string('submitassignment', 'assign'), 'get');
 967                  $o .= $this->output->box_start('boxaligncenter submithelp');
 968                  $o .= get_string('submitassignment_help', 'assign');
 969                  $o .= $this->output->box_end();
 970                  $o .= $this->output->box_end();
 971              }
 972          }
 973  
 974          $o .= $this->output->container_end();
 975          return $o;
 976      }
 977  
 978      /**
 979       * Output the attempt history chooser for this assignment
 980       *
 981       * @param assign_attempt_history_chooser $history
 982       * @return string
 983       */
 984      public function render_assign_attempt_history_chooser(assign_attempt_history_chooser $history) {
 985          $o = '';
 986  
 987          $context = $history->export_for_template($this);
 988          $o .= $this->render_from_template('mod_assign/attempt_history_chooser', $context);
 989  
 990          return $o;
 991      }
 992  
 993      /**
 994       * Output the attempt history for this assignment
 995       *
 996       * @param assign_attempt_history $history
 997       * @return string
 998       */
 999      public function render_assign_attempt_history(assign_attempt_history $history) {
1000          $o = '';
1001  
1002          // Don't show the last one because it is the current submission.
1003          array_pop($history->submissions);
1004  
1005          // Show newest to oldest.
1006          $history->submissions = array_reverse($history->submissions);
1007  
1008          if (empty($history->submissions)) {
1009              return '';
1010          }
1011  
1012          $containerid = 'attempthistory' . uniqid();
1013          $o .= $this->output->heading(get_string('attempthistory', 'assign'), 3);
1014          $o .= $this->box_start('attempthistory', $containerid);
1015  
1016          foreach ($history->submissions as $i => $submission) {
1017              $grade = null;
1018              foreach ($history->grades as $onegrade) {
1019                  if ($onegrade->attemptnumber == $submission->attemptnumber) {
1020                      if ($onegrade->grade != ASSIGN_GRADE_NOT_SET) {
1021                          $grade = $onegrade;
1022                      }
1023                      break;
1024                  }
1025              }
1026  
1027              if ($submission) {
1028                  $submissionsummary = userdate($submission->timemodified);
1029              } else {
1030                  $submissionsummary = get_string('nosubmission', 'assign');
1031              }
1032  
1033              $attemptsummaryparams = array('attemptnumber'=>$submission->attemptnumber+1,
1034                                            'submissionsummary'=>$submissionsummary);
1035              $o .= $this->heading(get_string('attemptheading', 'assign', $attemptsummaryparams), 4);
1036  
1037              $t = new html_table();
1038  
1039              if ($submission) {
1040                  $cell1content = get_string('submissionstatus', 'assign');
1041                  $cell2content = get_string('submissionstatus_' . $submission->status, 'assign');
1042                  $this->add_table_row_tuple($t, $cell1content, $cell2content);
1043  
1044                  foreach ($history->submissionplugins as $plugin) {
1045                      $pluginshowsummary = !$plugin->is_empty($submission) || !$plugin->allow_submissions();
1046                      if ($plugin->is_enabled() &&
1047                              $plugin->is_visible() &&
1048                              $plugin->has_user_summary() &&
1049                              $pluginshowsummary) {
1050  
1051                          $cell1content = $plugin->get_name();
1052                          $pluginsubmission = new assign_submission_plugin_submission($plugin,
1053                                                                                      $submission,
1054                                                                                      assign_submission_plugin_submission::SUMMARY,
1055                                                                                      $history->coursemoduleid,
1056                                                                                      $history->returnaction,
1057                                                                                      $history->returnparams);
1058                          $cell2content = $this->render($pluginsubmission);
1059                          $this->add_table_row_tuple($t, $cell1content, $cell2content);
1060                      }
1061                  }
1062              }
1063  
1064              if ($grade) {
1065                  // Heading 'feedback'.
1066                  $title = get_string('feedback', 'assign', $i);
1067                  $title .= $this->output->spacer(array('width'=>10));
1068                  if ($history->cangrade) {
1069                      // Edit previous feedback.
1070                      $returnparams = http_build_query($history->returnparams);
1071                      $urlparams = array('id' => $history->coursemoduleid,
1072                                     'rownum'=>$history->rownum,
1073                                     'useridlistid'=>$history->useridlistid,
1074                                     'attemptnumber'=>$grade->attemptnumber,
1075                                     'action'=>'grade',
1076                                     'returnaction'=>$history->returnaction,
1077                                     'returnparams'=>$returnparams);
1078                      $url = new moodle_url('/mod/assign/view.php', $urlparams);
1079                      $icon = new pix_icon('gradefeedback',
1080                                              get_string('editattemptfeedback', 'assign', $grade->attemptnumber+1),
1081                                              'mod_assign');
1082                      $title .= $this->output->action_icon($url, $icon);
1083                  }
1084                  $cell = new html_table_cell($title);
1085                  $cell->attributes['class'] = 'feedbacktitle';
1086                  $cell->colspan = 2;
1087                  $t->data[] = new html_table_row(array($cell));
1088  
1089                  // Grade.
1090                  $cell1content = get_string('grade');
1091                  $cell2content = $grade->gradefordisplay;
1092                  $this->add_table_row_tuple($t, $cell1content, $cell2content);
1093  
1094                  // Graded on.
1095                  $cell1content = get_string('gradedon', 'assign');
1096                  $cell2content = userdate($grade->timemodified);
1097                  $this->add_table_row_tuple($t, $cell1content, $cell2content);
1098  
1099                  // Graded by set to a real user. Not set can be empty or -1.
1100                  if (!empty($grade->grader) && is_object($grade->grader)) {
1101                      $cell1content = get_string('gradedby', 'assign');
1102                      $cell2content = $this->output->user_picture($grade->grader) .
1103                                      $this->output->spacer(array('width' => 30)) . fullname($grade->grader);
1104                      $this->add_table_row_tuple($t, $cell1content, $cell2content);
1105                  }
1106  
1107                  // Feedback from plugins.
1108                  foreach ($history->feedbackplugins as $plugin) {
1109                      if ($plugin->is_enabled() &&
1110                          $plugin->is_visible() &&
1111                          $plugin->has_user_summary() &&
1112                          !$plugin->is_empty($grade)) {
1113  
1114                          $pluginfeedback = new assign_feedback_plugin_feedback(
1115                              $plugin, $grade, assign_feedback_plugin_feedback::SUMMARY, $history->coursemoduleid,
1116                              $history->returnaction, $history->returnparams
1117                          );
1118  
1119                          $cell1content = $plugin->get_name();
1120                          $cell2content = $this->render($pluginfeedback);
1121                          $this->add_table_row_tuple($t, $cell1content, $cell2content);
1122                      }
1123  
1124                  }
1125  
1126              }
1127  
1128              $o .= html_writer::table($t);
1129          }
1130          $o .= $this->box_end();
1131  
1132          $this->page->requires->yui_module('moodle-mod_assign-history', 'Y.one("#' . $containerid . '").history');
1133  
1134          return $o;
1135      }
1136  
1137      /**
1138       * Render a submission plugin submission
1139       *
1140       * @param assign_submission_plugin_submission $submissionplugin
1141       * @return string
1142       */
1143      public function render_assign_submission_plugin_submission(assign_submission_plugin_submission $submissionplugin) {
1144          $o = '';
1145  
1146          if ($submissionplugin->view == assign_submission_plugin_submission::SUMMARY) {
1147              $showviewlink = false;
1148              $summary = $submissionplugin->plugin->view_summary($submissionplugin->submission,
1149                                                                 $showviewlink);
1150  
1151              $classsuffix = $submissionplugin->plugin->get_subtype() .
1152                             '_' .
1153                             $submissionplugin->plugin->get_type() .
1154                             '_' .
1155                             $submissionplugin->submission->id;
1156  
1157              $o .= $this->output->box_start('boxaligncenter plugincontentsummary summary_' . $classsuffix);
1158  
1159              $link = '';
1160              if ($showviewlink) {
1161                  $previewstr = get_string('viewsubmission', 'assign');
1162                  $icon = $this->output->pix_icon('t/preview', $previewstr);
1163  
1164                  $expandstr = get_string('viewfull', 'assign');
1165                  $expandicon = $this->output->pix_icon('t/switch_plus', $expandstr);
1166                  $options = array(
1167                      'class' => 'expandsummaryicon expand_' . $classsuffix,
1168                      'aria-label' => $expandstr,
1169                      'role' => 'button',
1170                      'aria-expanded' => 'false'
1171                  );
1172                  $o .= html_writer::link('', $expandicon, $options);
1173  
1174                  $jsparams = array($submissionplugin->plugin->get_subtype(),
1175                                    $submissionplugin->plugin->get_type(),
1176                                    $submissionplugin->submission->id);
1177  
1178                  $this->page->requires->js_init_call('M.mod_assign.init_plugin_summary', $jsparams);
1179  
1180                  $action = 'viewplugin' . $submissionplugin->plugin->get_subtype();
1181                  $returnparams = http_build_query($submissionplugin->returnparams);
1182                  $link .= '<noscript>';
1183                  $urlparams = array('id' => $submissionplugin->coursemoduleid,
1184                                     'sid'=>$submissionplugin->submission->id,
1185                                     'plugin'=>$submissionplugin->plugin->get_type(),
1186                                     'action'=>$action,
1187                                     'returnaction'=>$submissionplugin->returnaction,
1188                                     'returnparams'=>$returnparams);
1189                  $url = new moodle_url('/mod/assign/view.php', $urlparams);
1190                  $link .= $this->output->action_link($url, $icon);
1191                  $link .= '</noscript>';
1192  
1193                  $link .= $this->output->spacer(array('width'=>15));
1194              }
1195  
1196              $o .= $link . $summary;
1197              $o .= $this->output->box_end();
1198              if ($showviewlink) {
1199                  $o .= $this->output->box_start('boxaligncenter hidefull full_' . $classsuffix);
1200                  $collapsestr = get_string('viewsummary', 'assign');
1201                  $options = array(
1202                      'class' => 'expandsummaryicon contract_' . $classsuffix,
1203                      'aria-label' => $collapsestr,
1204                      'role' => 'button',
1205                      'aria-expanded' => 'true'
1206                  );
1207                  $collapseicon = $this->output->pix_icon('t/switch_minus', $collapsestr);
1208                  $o .= html_writer::link('', $collapseicon, $options);
1209  
1210                  $o .= $submissionplugin->plugin->view($submissionplugin->submission);
1211                  $o .= $this->output->box_end();
1212              }
1213          } else if ($submissionplugin->view == assign_submission_plugin_submission::FULL) {
1214              $o .= $this->output->box_start('boxaligncenter submissionfull');
1215              $o .= $submissionplugin->plugin->view($submissionplugin->submission);
1216              $o .= $this->output->box_end();
1217          }
1218  
1219          return $o;
1220      }
1221  
1222      /**
1223       * Render the grading table.
1224       *
1225       * @param assign_grading_table $table
1226       * @return string
1227       */
1228      public function render_assign_grading_table(assign_grading_table $table) {
1229          $o = '';
1230          $o .= $this->output->box_start('boxaligncenter gradingtable');
1231  
1232          $this->page->requires->js_init_call('M.mod_assign.init_grading_table', array());
1233          $this->page->requires->string_for_js('nousersselected', 'assign');
1234          $this->page->requires->string_for_js('batchoperationconfirmgrantextension', 'assign');
1235          $this->page->requires->string_for_js('batchoperationconfirmlock', 'assign');
1236          $this->page->requires->string_for_js('batchoperationconfirmremovesubmission', 'assign');
1237          $this->page->requires->string_for_js('batchoperationconfirmreverttodraft', 'assign');
1238          $this->page->requires->string_for_js('batchoperationconfirmunlock', 'assign');
1239          $this->page->requires->string_for_js('batchoperationconfirmaddattempt', 'assign');
1240          $this->page->requires->string_for_js('batchoperationconfirmdownloadselected', 'assign');
1241          $this->page->requires->string_for_js('batchoperationconfirmsetmarkingworkflowstate', 'assign');
1242          $this->page->requires->string_for_js('batchoperationconfirmsetmarkingallocation', 'assign');
1243          $this->page->requires->string_for_js('editaction', 'assign');
1244          foreach ($table->plugingradingbatchoperations as $plugin => $operations) {
1245              foreach ($operations as $operation => $description) {
1246                  $this->page->requires->string_for_js('batchoperationconfirm' . $operation,
1247                                                       'assignfeedback_' . $plugin);
1248              }
1249          }
1250          $o .= $this->flexible_table($table, $table->get_rows_per_page(), true);
1251          $o .= $this->output->box_end();
1252  
1253          return $o;
1254      }
1255  
1256      /**
1257       * Render a feedback plugin feedback
1258       *
1259       * @param assign_feedback_plugin_feedback $feedbackplugin
1260       * @return string
1261       */
1262      public function render_assign_feedback_plugin_feedback(assign_feedback_plugin_feedback $feedbackplugin) {
1263          $o = '';
1264  
1265          if ($feedbackplugin->view == assign_feedback_plugin_feedback::SUMMARY) {
1266              $showviewlink = false;
1267              $summary = $feedbackplugin->plugin->view_summary($feedbackplugin->grade, $showviewlink);
1268  
1269              $classsuffix = $feedbackplugin->plugin->get_subtype() .
1270                             '_' .
1271                             $feedbackplugin->plugin->get_type() .
1272                             '_' .
1273                             $feedbackplugin->grade->id;
1274              $o .= $this->output->box_start('boxaligncenter plugincontentsummary summary_' . $classsuffix);
1275  
1276              $link = '';
1277              if ($showviewlink) {
1278                  $previewstr = get_string('viewfeedback', 'assign');
1279                  $icon = $this->output->pix_icon('t/preview', $previewstr);
1280  
1281                  $expandstr = get_string('viewfull', 'assign');
1282                  $expandicon = $this->output->pix_icon('t/switch_plus', $expandstr);
1283                  $options = array(
1284                      'class' => 'expandsummaryicon expand_' . $classsuffix,
1285                      'aria-label' => $expandstr,
1286                      'role' => 'button',
1287                      'aria-expanded' => 'false'
1288                  );
1289                  $o .= html_writer::link('', $expandicon, $options);
1290  
1291                  $jsparams = array($feedbackplugin->plugin->get_subtype(),
1292                                    $feedbackplugin->plugin->get_type(),
1293                                    $feedbackplugin->grade->id);
1294                  $this->page->requires->js_init_call('M.mod_assign.init_plugin_summary', $jsparams);
1295  
1296                  $urlparams = array('id' => $feedbackplugin->coursemoduleid,
1297                                     'gid'=>$feedbackplugin->grade->id,
1298                                     'plugin'=>$feedbackplugin->plugin->get_type(),
1299                                     'action'=>'viewplugin' . $feedbackplugin->plugin->get_subtype(),
1300                                     'returnaction'=>$feedbackplugin->returnaction,
1301                                     'returnparams'=>http_build_query($feedbackplugin->returnparams));
1302                  $url = new moodle_url('/mod/assign/view.php', $urlparams);
1303                  $link .= '<noscript>';
1304                  $link .= $this->output->action_link($url, $icon);
1305                  $link .= '</noscript>';
1306  
1307                  $link .= $this->output->spacer(array('width'=>15));
1308              }
1309  
1310              $o .= $link . $summary;
1311              $o .= $this->output->box_end();
1312              if ($showviewlink) {
1313                  $o .= $this->output->box_start('boxaligncenter hidefull full_' . $classsuffix);
1314                  $collapsestr = get_string('viewsummary', 'assign');
1315                  $options = array(
1316                      'class' => 'expandsummaryicon contract_' . $classsuffix,
1317                      'aria-label' => $collapsestr,
1318                      'role' => 'button',
1319                      'aria-expanded' => 'true'
1320                  );
1321                  $collapseicon = $this->output->pix_icon('t/switch_minus', $collapsestr);
1322                  $o .= html_writer::link('', $collapseicon, $options);
1323  
1324                  $o .= $feedbackplugin->plugin->view($feedbackplugin->grade);
1325                  $o .= $this->output->box_end();
1326              }
1327          } else if ($feedbackplugin->view == assign_feedback_plugin_feedback::FULL) {
1328              $o .= $this->output->box_start('boxaligncenter feedbackfull');
1329              $o .= $feedbackplugin->plugin->view($feedbackplugin->grade);
1330              $o .= $this->output->box_end();
1331          }
1332  
1333          return $o;
1334      }
1335  
1336      /**
1337       * Render a course index summary
1338       *
1339       * @param assign_course_index_summary $indexsummary
1340       * @return string
1341       */
1342      public function render_assign_course_index_summary(assign_course_index_summary $indexsummary) {
1343          $o = '';
1344  
1345          $strplural = get_string('modulenameplural', 'assign');
1346          $strsectionname  = $indexsummary->courseformatname;
1347          $strduedate = get_string('duedate', 'assign');
1348          $strsubmission = get_string('submission', 'assign');
1349          $strgrade = get_string('grade');
1350  
1351          $table = new html_table();
1352          if ($indexsummary->usesections) {
1353              $table->head  = array ($strsectionname, $strplural, $strduedate, $strsubmission, $strgrade);
1354              $table->align = array ('left', 'left', 'center', 'right', 'right');
1355          } else {
1356              $table->head  = array ($strplural, $strduedate, $strsubmission, $strgrade);
1357              $table->align = array ('left', 'left', 'center', 'right');
1358          }
1359          $table->data = array();
1360  
1361          $currentsection = '';
1362          foreach ($indexsummary->assignments as $info) {
1363              $params = array('id' => $info['cmid']);
1364              $link = html_writer::link(new moodle_url('/mod/assign/view.php', $params),
1365                                        $info['cmname']);
1366              $due = $info['timedue'] ? userdate($info['timedue']) : '-';
1367  
1368              $printsection = '';
1369              if ($indexsummary->usesections) {
1370                  if ($info['sectionname'] !== $currentsection) {
1371                      if ($info['sectionname']) {
1372                          $printsection = $info['sectionname'];
1373                      }
1374                      if ($currentsection !== '') {
1375                          $table->data[] = 'hr';
1376                      }
1377                      $currentsection = $info['sectionname'];
1378                  }
1379              }
1380  
1381              if ($indexsummary->usesections) {
1382                  $row = array($printsection, $link, $due, $info['submissioninfo'], $info['gradeinfo']);
1383              } else {
1384                  $row = array($link, $due, $info['submissioninfo'], $info['gradeinfo']);
1385              }
1386              $table->data[] = $row;
1387          }
1388  
1389          $o .= html_writer::table($table);
1390  
1391          return $o;
1392      }
1393  
1394  
1395  
1396      /**
1397       * Internal function - creates htmls structure suitable for YUI tree.
1398       *
1399       * @param assign_files $tree
1400       * @param array $dir
1401       * @return string
1402       */
1403      protected function htmllize_tree(assign_files $tree, $dir) {
1404          global $CFG;
1405          $yuiconfig = array();
1406          $yuiconfig['type'] = 'html';
1407  
1408          if (empty($dir['subdirs']) and empty($dir['files'])) {
1409              return '';
1410          }
1411  
1412          $result = '<ul>';
1413          foreach ($dir['subdirs'] as $subdir) {
1414              $image = $this->output->pix_icon(file_folder_icon(),
1415                                               $subdir['dirname'],
1416                                               'moodle',
1417                                               array('class'=>'icon'));
1418              $result .= '<li yuiConfig=\'' . json_encode($yuiconfig) . '\'>' .
1419                         '<div>' . $image . ' ' . s($subdir['dirname']) . '</div> ' .
1420                         $this->htmllize_tree($tree, $subdir) .
1421                         '</li>';
1422          }
1423  
1424          foreach ($dir['files'] as $file) {
1425              $filename = $file->get_filename();
1426              if ($CFG->enableplagiarism) {
1427                  require_once($CFG->libdir.'/plagiarismlib.php');
1428                  $plagiarismlinks = plagiarism_get_links(array('userid'=>$file->get_userid(),
1429                                                               'file'=>$file,
1430                                                               'cmid'=>$tree->cm->id,
1431                                                               'course'=>$tree->course));
1432              } else {
1433                  $plagiarismlinks = '';
1434              }
1435              $image = $this->output->pix_icon(file_file_icon($file),
1436                                               $filename,
1437                                               'moodle',
1438                                               array('class'=>'icon'));
1439              $result .= '<li yuiConfig=\'' . json_encode($yuiconfig) . '\'>' .
1440                  '<div>' .
1441                      '<div class="fileuploadsubmission">' . $image . ' ' .
1442                      $file->fileurl . ' ' .
1443                      $plagiarismlinks . ' ' .
1444                      $file->portfoliobutton . ' ' .
1445                      '</div>' .
1446                      '<div class="fileuploadsubmissiontime">' . $file->timemodified . '</div>' .
1447                  '</div>' .
1448              '</li>';
1449          }
1450  
1451          $result .= '</ul>';
1452  
1453          return $result;
1454      }
1455  
1456      /**
1457       * Helper method dealing with the fact we can not just fetch the output of flexible_table
1458       *
1459       * @param flexible_table $table The table to render
1460       * @param int $rowsperpage How many assignments to render in a page
1461       * @param bool $displaylinks - Whether to render links in the table
1462       *                             (e.g. downloads would not enable this)
1463       * @return string HTML
1464       */
1465      protected function flexible_table(flexible_table $table, $rowsperpage, $displaylinks) {
1466  
1467          $o = '';
1468          ob_start();
1469          $table->out($rowsperpage, $displaylinks);
1470          $o = ob_get_contents();
1471          ob_end_clean();
1472  
1473          return $o;
1474      }
1475  
1476      /**
1477       * Helper method dealing with the fact we can not just fetch the output of moodleforms
1478       *
1479       * @param moodleform $mform
1480       * @return string HTML
1481       */
1482      protected function moodleform(moodleform $mform) {
1483  
1484          $o = '';
1485          ob_start();
1486          $mform->display();
1487          $o = ob_get_contents();
1488          ob_end_clean();
1489  
1490          return $o;
1491      }
1492  
1493      /**
1494       * Defer to template..
1495       *
1496       * @param grading_app $app - All the data to render the grading app.
1497       */
1498      public function render_grading_app(grading_app $app) {
1499          $context = $app->export_for_template($this);
1500          return $this->render_from_template('mod_assign/grading_app', $context);
1501      }
1502  }
1503