PageRenderTime 33ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/mod/assign/renderer.php

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