diff --git a/mod/assign/classes/output/assign_header.php b/mod/assign/classes/output/assign_header.php new file mode 100644 index 00000000000..eece1de830a --- /dev/null +++ b/mod/assign/classes/output/assign_header.php @@ -0,0 +1,82 @@ +. + +/** + * This file contains the definition for the renderable assign header. + * + * @package mod_assign + * @copyright 2020 Matt Porritt + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +namespace mod_assign\output; + +/** + * This file contains the definition for the renderable assign header. + * + * @package mod_assign + * @copyright 2012 NetSpot {@link http://www.netspot.com.au} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class assign_header implements \renderable { + /** @var \stdClass The assign record. */ + public $assign; + /** @var mixed \context|null the context record. */ + public $context; + /** @var bool $showintro Show or hide the intro. */ + public $showintro; + /** @var int coursemoduleid The course module id. */ + public $coursemoduleid; + /** @var string $subpage Optional subpage (extra level in the breadcrumbs). */ + public $subpage; + /** @var string $preface Optional preface (text to show before the heading). */ + public $preface; + /** @var string $postfix Optional postfix (text to show after the intro). */ + public $postfix; + /** @var \moodle_url|null $subpageurl link for the sub page */ + public $subpageurl; + + /** + * Constructor + * + * @param \stdClass $assign The assign database record. + * @param \context|null $context The course module context. + * @param bool $showintro Show or hide the intro. + * @param int $coursemoduleid The course module id. + * @param string $subpage An optional sub page in the navigation. + * @param string $preface An optional preface to show before the heading. + * @param string $postfix An optional postfix to show after the intro. + * @param \moodle_url|null $subpageurl An optional sub page URL link for the subpage. + */ + public function __construct( + \stdClass $assign, + $context, + $showintro, + $coursemoduleid, + $subpage = '', + $preface = '', + $postfix = '', + \moodle_url $subpageurl = null + ) { + $this->assign = $assign; + $this->context = $context; + $this->showintro = $showintro; + $this->coursemoduleid = $coursemoduleid; + $this->subpage = $subpage; + $this->preface = $preface; + $this->postfix = $postfix; + $this->subpageurl = $subpageurl; + } +} diff --git a/mod/assign/classes/output/assign_submission_status.php b/mod/assign/classes/output/assign_submission_status.php new file mode 100644 index 00000000000..13fb6bdafb4 --- /dev/null +++ b/mod/assign/classes/output/assign_submission_status.php @@ -0,0 +1,197 @@ +. + +/** + * This file contains the definition for the renderable assign submission status. + * + * @package mod_assign + * @copyright 2020 Matt Porritt + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +namespace mod_assign\output; + +/** + * This file contains the definition for the renderable assign submission status. + * + * @package mod_assign + * @copyright 2012 NetSpot {@link http://www.netspot.com.au} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class assign_submission_status implements \renderable { + /** @var int STUDENT_VIEW */ + const STUDENT_VIEW = 10; + /** @var int GRADER_VIEW */ + const GRADER_VIEW = 20; + + /** @var int allowsubmissionsfromdate */ + public $allowsubmissionsfromdate = 0; + /** @var bool alwaysshowdescription */ + public $alwaysshowdescription = false; + /** @var mixed the submission info (may be null or an integer) */ + public $submission = null; + /** @var boolean teamsubmissionenabled - true or false */ + public $teamsubmissionenabled = false; + /** @var \stdClass teamsubmission the team submission info (may be null) */ + public $teamsubmission = null; + /** @var mixed submissiongroup the submission group info (may be null) */ + public $submissiongroup = null; + /** @var array submissiongroupmemberswhoneedtosubmit list of users who still need to submit */ + public $submissiongroupmemberswhoneedtosubmit = array(); + /** @var bool submissionsenabled */ + public $submissionsenabled = false; + /** @var bool locked */ + public $locked = false; + /** @var bool graded */ + public $graded = false; + /** @var int duedate */ + public $duedate = 0; + /** @var int cutoffdate */ + public $cutoffdate = 0; + /** @var array submissionplugins - the list of submission plugins */ + public $submissionplugins = array(); + /** @var string returnaction */ + public $returnaction = ''; + /** @var string returnparams */ + public $returnparams = array(); + /** @var int courseid */ + public $courseid = 0; + /** @var int coursemoduleid */ + public $coursemoduleid = 0; + /** @var int the view (STUDENT_VIEW OR GRADER_VIEW) */ + public $view = self::STUDENT_VIEW; + /** @var bool canviewfullnames */ + public $canviewfullnames = false; + /** @var bool canedit */ + public $canedit = false; + /** @var bool cansubmit */ + public $cansubmit = false; + /** @var int extensionduedate */ + public $extensionduedate = 0; + /** @var \context context */ + public $context = 0; + /** @var bool blindmarking - Should we hide student identities from graders? */ + public $blindmarking = false; + /** @var string gradingcontrollerpreview */ + public $gradingcontrollerpreview = ''; + /** @var string attemptreopenmethod */ + public $attemptreopenmethod = 'none'; + /** @var int maxattempts */ + public $maxattempts = -1; + /** @var string gradingstatus */ + public $gradingstatus = ''; + /** @var bool preventsubmissionnotingroup */ + public $preventsubmissionnotingroup = 0; + /** @var array usergroups */ + public $usergroups = array(); + + /** + * Constructor + * + * @param int $allowsubmissionsfromdate + * @param bool $alwaysshowdescription + * @param mixed $submission + * @param bool $teamsubmissionenabled + * @param \stdClass $teamsubmission + * @param mixed $submissiongroup + * @param array $submissiongroupmemberswhoneedtosubmit + * @param bool $submissionsenabled + * @param bool $locked + * @param bool $graded + * @param int $duedate + * @param int $cutoffdate + * @param array $submissionplugins + * @param string $returnaction + * @param array $returnparams + * @param int $coursemoduleid + * @param int $courseid + * @param string $view + * @param bool $canedit + * @param bool $cansubmit + * @param bool $canviewfullnames + * @param int $extensionduedate Any extension to the due date granted for this user. + * @param \context $context Any extension to the due date granted for this user. + * @param bool $blindmarking Should we hide student identities from graders? + * @param string $gradingcontrollerpreview + * @param string $attemptreopenmethod The method of reopening student attempts. + * @param int $maxattempts How many attempts can a student make? + * @param string $gradingstatus The submission status (ie. Graded, Not Released etc). + * @param bool $preventsubmissionnotingroup Prevent submission if user is not in a group. + * @param array $usergroups Array containing all groups the user is assigned to. + */ + public function __construct( + $allowsubmissionsfromdate, + $alwaysshowdescription, + $submission, + $teamsubmissionenabled, + $teamsubmission, + $submissiongroup, + $submissiongroupmemberswhoneedtosubmit, + $submissionsenabled, + $locked, + $graded, + $duedate, + $cutoffdate, + $submissionplugins, + $returnaction, + $returnparams, + $coursemoduleid, + $courseid, + $view, + $canedit, + $cansubmit, + $canviewfullnames, + $extensionduedate, + $context, + $blindmarking, + $gradingcontrollerpreview, + $attemptreopenmethod, + $maxattempts, + $gradingstatus, + $preventsubmissionnotingroup, + $usergroups + ) { + $this->allowsubmissionsfromdate = $allowsubmissionsfromdate; + $this->alwaysshowdescription = $alwaysshowdescription; + $this->submission = $submission; + $this->teamsubmissionenabled = $teamsubmissionenabled; + $this->teamsubmission = $teamsubmission; + $this->submissiongroup = $submissiongroup; + $this->submissiongroupmemberswhoneedtosubmit = $submissiongroupmemberswhoneedtosubmit; + $this->submissionsenabled = $submissionsenabled; + $this->locked = $locked; + $this->graded = $graded; + $this->duedate = $duedate; + $this->cutoffdate = $cutoffdate; + $this->submissionplugins = $submissionplugins; + $this->returnaction = $returnaction; + $this->returnparams = $returnparams; + $this->coursemoduleid = $coursemoduleid; + $this->courseid = $courseid; + $this->view = $view; + $this->canedit = $canedit; + $this->cansubmit = $cansubmit; + $this->canviewfullnames = $canviewfullnames; + $this->extensionduedate = $extensionduedate; + $this->context = $context; + $this->blindmarking = $blindmarking; + $this->gradingcontrollerpreview = $gradingcontrollerpreview; + $this->attemptreopenmethod = $attemptreopenmethod; + $this->maxattempts = $maxattempts; + $this->gradingstatus = $gradingstatus; + $this->preventsubmissionnotingroup = $preventsubmissionnotingroup; + $this->usergroups = $usergroups; + } +} diff --git a/mod/assign/classes/output/renderer.php b/mod/assign/classes/output/renderer.php new file mode 100644 index 00000000000..6fb3a41af7b --- /dev/null +++ b/mod/assign/classes/output/renderer.php @@ -0,0 +1,1483 @@ +. + +/** + * This file contains a renderer for the assignment class + * + * @package mod_assign + * @copyright 2012 NetSpot {@link http://www.netspot.com.au} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace mod_assign\output; + +require_once($CFG->dirroot . '/mod/assign/locallib.php'); + +use \mod_assign\output\grading_app; + +/** + * A custom renderer class that extends the plugin_renderer_base and is used by the assign module. + * + * @package mod_assign + * @copyright 2012 NetSpot {@link http://www.netspot.com.au} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class renderer extends \plugin_renderer_base { + + /** + * Rendering assignment files + * + * @param \context $context + * @param int $userid + * @param string $filearea + * @param string $component + * @param stdClass $course + * @param stdClass $coursemodule + * @return string + */ + public function assign_files(\context $context, $userid, $filearea, $component, $course = null, $coursemodule = null) { + return $this->render(new \assign_files($context, $userid, $filearea, $component, $course, $coursemodule)); + } + + /** + * Rendering assignment files + * + * @param \assign_files $tree + * @return string + */ + public function render_assign_files(\assign_files $tree) { + $this->htmlid = \html_writer::random_id('assign_files_tree'); + $this->page->requires->js_init_call('M.mod_assign.init_tree', array(true, $this->htmlid)); + $html = '
'; + $html .= $this->htmllize_tree($tree, $tree->dir); + $html .= '
'; + + if ($tree->portfolioform) { + $html .= $tree->portfolioform; + } + return $html; + } + + /** + * Utility function to add a row of data to a table with 2 columns where the first column is the table's header. + * Modified the table param and does not return a value. + * + * @param \html_table $table The table to append the row of data to + * @param string $first The first column text + * @param string $second The second column text + * @param array $firstattributes The first column attributes (optional) + * @param array $secondattributes The second column attributes (optional) + * @return void + */ + private function add_table_row_tuple(\html_table $table, $first, $second, $firstattributes = [], + $secondattributes = []) { + $row = new \html_table_row(); + $cell1 = new \html_table_cell($first); + $cell1->header = true; + if (!empty($firstattributes)) { + $cell1->attributes = $firstattributes; + } + $cell2 = new \html_table_cell($second); + if (!empty($secondattributes)) { + $cell2->attributes = $secondattributes; + } + $row->cells = array($cell1, $cell2); + $table->data[] = $row; + } + + /** + * Render a grading message notification + * @param \assign_gradingmessage $result The result to render + * @return string + */ + public function render_assign_gradingmessage(\assign_gradingmessage $result) { + $urlparams = array('id' => $result->coursemoduleid, 'action'=>'grading'); + if (!empty($result->page)) { + $urlparams['page'] = $result->page; + } + $url = new \moodle_url('/mod/assign/view.php', $urlparams); + $classes = $result->gradingerror ? 'notifyproblem' : 'notifysuccess'; + + $o = ''; + $o .= $this->output->heading($result->heading, 4); + $o .= $this->output->notification($result->message, $classes); + $o .= $this->output->continue_button($url); + return $o; + } + + /** + * Render the generic form + * @param \assign_form $form The form to render + * @return string + */ + public function render_assign_form(\assign_form $form) { + $o = ''; + if ($form->jsinitfunction) { + $this->page->requires->js_init_call($form->jsinitfunction, array()); + } + $o .= $this->output->box_start('boxaligncenter ' . $form->classname); + $o .= $this->moodleform($form->form); + $o .= $this->output->box_end(); + return $o; + } + + /** + * Render the user summary + * + * @param \assign_user_summary $summary The user summary to render + * @return string + */ + public function render_assign_user_summary(\assign_user_summary $summary) { + $o = ''; + $supendedclass = ''; + $suspendedicon = ''; + + if (!$summary->user) { + return; + } + + if ($summary->suspendeduser) { + $supendedclass = ' usersuspended'; + $suspendedstring = get_string('userenrolmentsuspended', 'grades'); + $suspendedicon = ' ' . $this->pix_icon('i/enrolmentsuspended', $suspendedstring); + } + $o .= $this->output->container_start('usersummary'); + $o .= $this->output->box_start('boxaligncenter usersummarysection'.$supendedclass); + if ($summary->blindmarking) { + $o .= get_string('hiddenuser', 'assign') . $summary->uniqueidforuser.$suspendedicon; + } else { + $o .= $this->output->user_picture($summary->user); + $o .= $this->output->spacer(array('width'=>30)); + $urlparams = array('id' => $summary->user->id, 'course'=>$summary->courseid); + $url = new \moodle_url('/user/view.php', $urlparams); + $fullname = fullname($summary->user, $summary->viewfullnames); + $extrainfo = array(); + foreach ($summary->extrauserfields as $extrafield) { + $extrainfo[] = $summary->user->$extrafield; + } + if (count($extrainfo)) { + $fullname .= ' (' . implode(', ', $extrainfo) . ')'; + } + $fullname .= $suspendedicon; + $o .= $this->output->action_link($url, $fullname); + } + $o .= $this->output->box_end(); + $o .= $this->output->container_end(); + + return $o; + } + + /** + * Render the submit for grading page + * + * @param \assign_submit_for_grading_page $page + * @return string + */ + public function render_assign_submit_for_grading_page($page) { + $o = ''; + + $o .= $this->output->container_start('submitforgrading'); + $o .= $this->output->heading(get_string('confirmsubmissionheading', 'assign'), 3); + + $cancelurl = new \moodle_url('/mod/assign/view.php', array('id' => $page->coursemoduleid)); + if (count($page->notifications)) { + // At least one of the submission plugins is not ready for submission. + + $o .= $this->output->heading(get_string('submissionnotready', 'assign'), 4); + + foreach ($page->notifications as $notification) { + $o .= $this->output->notification($notification); + } + + $o .= $this->output->continue_button($cancelurl); + } else { + // All submission plugins ready - show the confirmation form. + $o .= $this->moodleform($page->confirmform); + } + $o .= $this->output->container_end(); + + return $o; + } + + /** + * Page is done - render the footer. + * + * @return void + */ + public function render_footer() { + return $this->output->footer(); + } + + /** + * Render the header. + * + * @param assign_header $header + * @return string + */ + public function render_assign_header(assign_header $header) { + global $USER; + + $o = ''; + + if ($header->subpage) { + $this->page->navbar->add($header->subpage, $header->subpageurl); + $args = ['contextname' => $header->context->get_context_name(false, true), 'subpage' => $header->subpage]; + $title = get_string('subpagetitle', 'assign', $args); + } else { + $title = $header->context->get_context_name(false, true); + } + $courseshortname = $header->context->get_course_context()->get_context_name(false, true); + $title = $courseshortname . ': ' . $title; + $heading = format_string($header->assign->name, false, array('context' => $header->context)); + + $this->page->set_title($title); + $this->page->set_heading($this->page->course->fullname); + + $o .= $this->output->header(); + $o .= $this->output->heading($heading); + + // Show the activity information output component. + $modinfo = get_fast_modinfo($header->assign->course); + $cm = $modinfo->get_cm($header->coursemoduleid); + $cmcompletion = \core_completion\cm_completion_details::get_instance($cm, $USER->id); + $activitydates = \core\activity_dates::get_dates_for_module($cm, $USER->id); + $o .= $this->output->activity_information($cm, $cmcompletion, $activitydates); + + if ($header->preface) { + $o .= $header->preface; + } + + if ($header->showintro) { + $o .= $this->output->box_start('generalbox boxaligncenter', 'intro'); + $o .= format_module_intro('assign', $header->assign, $header->coursemoduleid); + $o .= $header->postfix; + $o .= $this->output->box_end(); + } + + return $o; + } + + /** + * Render the header for an individual plugin. + * + * @param \assign_plugin_header $header + * @return string + */ + public function render_assign_plugin_header(\assign_plugin_header $header) { + $o = $header->plugin->view_header(); + return $o; + } + + /** + * Render a table containing the current status of the grading process. + * + * @param \assign_grading_summary $summary + * @return string + */ + public function render_assign_grading_summary(\assign_grading_summary $summary) { + // Create a table for the data. + $o = ''; + $o .= $this->output->container_start('gradingsummary'); + $o .= $this->output->heading(get_string('gradingsummary', 'assign'), 3); + $o .= $this->output->box_start('boxaligncenter gradingsummarytable'); + $t = new \html_table(); + $t->attributes['class'] = 'generaltable table-bordered'; + + // Visibility Status. + $cell1content = get_string('hiddenfromstudents'); + $cell2content = (!$summary->isvisible) ? get_string('yes') : get_string('no'); + $this->add_table_row_tuple($t, $cell1content, $cell2content); + + // Status. + if ($summary->teamsubmission) { + if ($summary->warnofungroupedusers === \assign_grading_summary::WARN_GROUPS_REQUIRED) { + $o .= $this->output->notification(get_string('ungroupedusers', 'assign')); + } else if ($summary->warnofungroupedusers === \assign_grading_summary::WARN_GROUPS_OPTIONAL) { + $o .= $this->output->notification(get_string('ungroupedusersoptional', 'assign')); + } + $cell1content = get_string('numberofteams', 'assign'); + } else { + $cell1content = get_string('numberofparticipants', 'assign'); + } + + $cell2content = $summary->participantcount; + $this->add_table_row_tuple($t, $cell1content, $cell2content); + + // Drafts count and dont show drafts count when using offline assignment. + if ($summary->submissiondraftsenabled && $summary->submissionsenabled) { + $cell1content = get_string('numberofdraftsubmissions', 'assign'); + $cell2content = $summary->submissiondraftscount; + $this->add_table_row_tuple($t, $cell1content, $cell2content); + } + + // Submitted for grading. + if ($summary->submissionsenabled) { + $cell1content = get_string('numberofsubmittedassignments', 'assign'); + $cell2content = $summary->submissionssubmittedcount; + $this->add_table_row_tuple($t, $cell1content, $cell2content); + + if (!$summary->teamsubmission) { + $cell1content = get_string('numberofsubmissionsneedgrading', 'assign'); + $cell2content = $summary->submissionsneedgradingcount; + $this->add_table_row_tuple($t, $cell1content, $cell2content); + } + } + + $time = time(); + if ($summary->duedate) { + // Time remaining. + $duedate = $summary->duedate; + $cell1content = get_string('timeremaining', 'assign'); + if ($summary->courserelativedatesmode) { + $cell2content = get_string('relativedatessubmissiontimeleft', 'mod_assign'); + } else { + if ($duedate - $time <= 0) { + $cell2content = get_string('assignmentisdue', 'assign'); + } else { + $cell2content = format_time($duedate - $time); + } + } + + $this->add_table_row_tuple($t, $cell1content, $cell2content); + + if ($duedate < $time) { + $cell1content = get_string('latesubmissions', 'assign'); + $cutoffdate = $summary->cutoffdate; + if ($cutoffdate) { + if ($cutoffdate > $time) { + $cell2content = get_string('latesubmissionsaccepted', 'assign', userdate($summary->cutoffdate)); + } else { + $cell2content = get_string('nomoresubmissionsaccepted', 'assign'); + } + + $this->add_table_row_tuple($t, $cell1content, $cell2content); + } + } + + } + + // All done - write the table. + $o .= \html_writer::table($t); + $o .= $this->output->box_end(); + + // Link to the grading page. + $o .= \html_writer::start_tag('center'); + $o .= $this->output->container_start('submissionlinks'); + $urlparams = array('id' => $summary->coursemoduleid, 'action' => 'grading'); + $url = new \moodle_url('/mod/assign/view.php', $urlparams); + $o .= \html_writer::link($url, get_string('viewgrading', 'mod_assign'), + ['class' => 'btn btn-secondary']); + if ($summary->cangrade) { + $urlparams = array('id' => $summary->coursemoduleid, 'action' => 'grader'); + $url = new \moodle_url('/mod/assign/view.php', $urlparams); + $o .= \html_writer::link($url, get_string('gradeverb'), + ['class' => 'btn btn-primary ml-1']); + } + $o .= $this->output->container_end(); + + // Close the container and insert a spacer. + $o .= $this->output->container_end(); + $o .= \html_writer::end_tag('center'); + + return $o; + } + + /** + * Render a table containing all the current grades and feedback. + * + * @param \assign_feedback_status $status + * @return string + */ + public function render_assign_feedback_status(\assign_feedback_status $status) { + $o = ''; + + $o .= $this->output->container_start('feedback'); + $o .= $this->output->heading(get_string('feedback', 'assign'), 3); + $o .= $this->output->box_start('boxaligncenter feedbacktable'); + $t = new \html_table(); + + // Grade. + if (isset($status->gradefordisplay)) { + $cell1content = get_string('gradenoun'); + $cell2content = $status->gradefordisplay; + $this->add_table_row_tuple($t, $cell1content, $cell2content); + + // Grade date. + $cell1content = get_string('gradedon', 'assign'); + $cell2content = userdate($status->gradeddate); + $this->add_table_row_tuple($t, $cell1content, $cell2content); + } + + if ($status->grader) { + // Grader. + $cell1content = get_string('gradedby', 'assign'); + $cell2content = $this->output->user_picture($status->grader) . + $this->output->spacer(array('width' => 30)) . + fullname($status->grader, $status->canviewfullnames); + $this->add_table_row_tuple($t, $cell1content, $cell2content); + } + + foreach ($status->feedbackplugins as $plugin) { + if ($plugin->is_enabled() && + $plugin->is_visible() && + $plugin->has_user_summary() && + !empty($status->grade) && + !$plugin->is_empty($status->grade)) { + + $displaymode = \assign_feedback_plugin_feedback::SUMMARY; + $pluginfeedback = new \assign_feedback_plugin_feedback($plugin, + $status->grade, + $displaymode, + $status->coursemoduleid, + $status->returnaction, + $status->returnparams); + $cell1content = $plugin->get_name(); + $cell2content = $this->render($pluginfeedback); + $this->add_table_row_tuple($t, $cell1content, $cell2content); + } + } + + $o .= \html_writer::table($t); + $o .= $this->output->box_end(); + + $o .= $this->output->container_end(); + return $o; + } + + /** + * Render a compact view of the current status of the submission. + * + * @param \assign_submission_status_compact $status + * @return string + */ + public function render_assign_submission_status_compact(\assign_submission_status_compact $status) { + $o = ''; + $o .= $this->output->container_start('submissionstatustable'); + $o .= $this->output->heading(get_string('submission', 'assign'), 3); + $time = time(); + + if ($status->teamsubmissionenabled) { + $group = $status->submissiongroup; + if ($group) { + $team = format_string($group->name, false, $status->context); + } else if ($status->preventsubmissionnotingroup) { + if (count($status->usergroups) == 0) { + $team = '' . get_string('noteam', 'assign') . ''; + } else if (count($status->usergroups) > 1) { + $team = '' . get_string('multipleteams', 'assign') . ''; + } + } else { + $team = get_string('defaultteam', 'assign'); + } + $o .= $this->output->container(get_string('teamname', 'assign', $team), 'teamname'); + } + + if (!$status->teamsubmissionenabled) { + if ($status->submission && $status->submission->status != ASSIGN_SUBMISSION_STATUS_NEW) { + $statusstr = get_string('submissionstatus_' . $status->submission->status, 'assign'); + $o .= $this->output->container($statusstr, 'submissionstatus' . $status->submission->status); + } else { + if (!$status->submissionsenabled) { + $o .= $this->output->container(get_string('noonlinesubmissions', 'assign'), 'submissionstatus'); + } else { + $o .= $this->output->container(get_string('noattempt', 'assign'), 'submissionstatus'); + } + } + } else { + $group = $status->submissiongroup; + if (!$group && $status->preventsubmissionnotingroup) { + $o .= $this->output->container(get_string('nosubmission', 'assign'), 'submissionstatus'); + } else if ($status->teamsubmission && $status->teamsubmission->status != ASSIGN_SUBMISSION_STATUS_NEW) { + $teamstatus = $status->teamsubmission->status; + $submissionsummary = get_string('submissionstatus_' . $teamstatus, 'assign'); + $groupid = 0; + if ($status->submissiongroup) { + $groupid = $status->submissiongroup->id; + } + + $members = $status->submissiongroupmemberswhoneedtosubmit; + $userslist = array(); + foreach ($members as $member) { + $urlparams = array('id' => $member->id, 'course' => $status->courseid); + $url = new \moodle_url('/user/view.php', $urlparams); + if ($status->view == assign_submission_status::GRADER_VIEW && $status->blindmarking) { + $userslist[] = $member->alias; + } else { + $fullname = fullname($member, $status->canviewfullnames); + $userslist[] = $this->output->action_link($url, $fullname); + } + } + if (count($userslist) > 0) { + $userstr = join(', ', $userslist); + $formatteduserstr = get_string('userswhoneedtosubmit', 'assign', $userstr); + $submissionsummary .= $this->output->container($formatteduserstr); + } + $o .= $this->output->container($submissionsummary, 'submissionstatus' . $status->teamsubmission->status); + } else { + if (!$status->submissionsenabled) { + $o .= $this->output->container(get_string('noonlinesubmissions', 'assign'), 'submissionstatus'); + } else { + $o .= $this->output->container(get_string('nosubmission', 'assign'), 'submissionstatus'); + } + } + } + + // Is locked? + if ($status->locked) { + $o .= $this->output->container(get_string('submissionslocked', 'assign'), 'submissionlocked'); + } + + // Grading status. + $statusstr = ''; + $classname = 'gradingstatus'; + if ($status->gradingstatus == ASSIGN_GRADING_STATUS_GRADED || + $status->gradingstatus == ASSIGN_GRADING_STATUS_NOT_GRADED) { + $statusstr = get_string($status->gradingstatus, 'assign'); + } else { + $gradingstatus = 'markingworkflowstate' . $status->gradingstatus; + $statusstr = get_string($gradingstatus, 'assign'); + } + if ($status->gradingstatus == ASSIGN_GRADING_STATUS_GRADED || + $status->gradingstatus == ASSIGN_MARKING_WORKFLOW_STATE_RELEASED) { + $classname = 'submissiongraded'; + } else { + $classname = 'submissionnotgraded'; + } + + $o .= $this->output->container($statusstr, $classname); + + $submission = $status->teamsubmission ? $status->teamsubmission : $status->submission; + $duedate = $status->duedate; + if ($duedate > 0) { + + if ($status->extensionduedate) { + // Extension date. + $duedate = $status->extensionduedate; + } + + // Time remaining. + $classname = 'timeremaining'; + if ($duedate - $time <= 0) { + if (!$submission || + $submission->status != ASSIGN_SUBMISSION_STATUS_SUBMITTED) { + if ($status->submissionsenabled) { + $remaining = get_string('overdue', 'assign', format_time($time - $duedate)); + $classname = 'overdue'; + } else { + $remaining = get_string('duedatereached', 'assign'); + } + } else { + if ($submission->timemodified > $duedate) { + $remaining = get_string('submittedlate', + 'assign', + format_time($submission->timemodified - $duedate)); + $classname = 'latesubmission'; + } else { + $remaining = get_string('submittedearly', + 'assign', + format_time($submission->timemodified - $duedate)); + $classname = 'earlysubmission'; + } + } + } else { + $remaining = get_string('paramtimeremaining', 'assign', format_time($duedate - $time)); + } + $o .= $this->output->container($remaining, $classname); + } + + // Show graders whether this submission is editable by students. + if ($status->view == assign_submission_status::GRADER_VIEW) { + if ($status->canedit) { + $o .= $this->output->container(get_string('submissioneditable', 'assign'), 'submissioneditable'); + } else { + $o .= $this->output->container(get_string('submissionnoteditable', 'assign'), 'submissionnoteditable'); + } + } + + // Grading criteria preview. + if (!empty($status->gradingcontrollerpreview)) { + $o .= $this->output->container($status->gradingcontrollerpreview, 'gradingmethodpreview'); + } + + if ($submission) { + + if (!$status->teamsubmission || $status->submissiongroup != false || !$status->preventsubmissionnotingroup) { + foreach ($status->submissionplugins as $plugin) { + $pluginshowsummary = !$plugin->is_empty($submission) || !$plugin->allow_submissions(); + if ($plugin->is_enabled() && + $plugin->is_visible() && + $plugin->has_user_summary() && + $pluginshowsummary + ) { + + $displaymode = \assign_submission_plugin_submission::SUMMARY; + $pluginsubmission = new \assign_submission_plugin_submission($plugin, + $submission, + $displaymode, + $status->coursemoduleid, + $status->returnaction, + $status->returnparams); + $plugincomponent = $plugin->get_subtype() . '_' . $plugin->get_type(); + $o .= $this->output->container($this->render($pluginsubmission), 'assignsubmission ' . $plugincomponent); + } + } + } + } + + $o .= $this->output->container_end(); + return $o; + } + + /** + * Render a table containing the current status of the submission. + * + * @param assign_submission_status $status + * @return string + */ + public function render_assign_submission_status(assign_submission_status $status) { + $o = ''; + $o .= $this->output->container_start('submissionstatustable'); + $o .= $this->output->heading(get_string('submissionstatusheading', 'assign'), 3); + $time = time(); + + $o .= $this->output->box_start('boxaligncenter submissionsummarytable'); + + $t = new \html_table(); + $t->attributes['class'] = 'generaltable table-bordered'; + + $warningmsg = ''; + if ($status->teamsubmissionenabled) { + $cell1content = get_string('submissionteam', 'assign'); + $group = $status->submissiongroup; + if ($group) { + $cell2content = format_string($group->name, false, $status->context); + } else if ($status->preventsubmissionnotingroup) { + if (count($status->usergroups) == 0) { + $notification = new \core\output\notification(get_string('noteam', 'assign'), 'error'); + $notification->set_show_closebutton(false); + $warningmsg = $this->output->notification(get_string('noteam_desc', 'assign'), 'error'); + } else if (count($status->usergroups) > 1) { + $notification = new \core\output\notification(get_string('multipleteams', 'assign'), 'error'); + $notification->set_show_closebutton(false); + $warningmsg = $this->output->notification(get_string('multipleteams_desc', 'assign'), 'error'); + } + $cell2content = $this->output->render($notification); + } else { + $cell2content = get_string('defaultteam', 'assign'); + } + + $this->add_table_row_tuple($t, $cell1content, $cell2content); + } + + if ($status->attemptreopenmethod != ASSIGN_ATTEMPT_REOPEN_METHOD_NONE) { + $currentattempt = 1; + if (!$status->teamsubmissionenabled) { + if ($status->submission) { + $currentattempt = $status->submission->attemptnumber + 1; + } + } else { + if ($status->teamsubmission) { + $currentattempt = $status->teamsubmission->attemptnumber + 1; + } + } + + $cell1content = get_string('attemptnumber', 'assign'); + $maxattempts = $status->maxattempts; + if ($maxattempts == ASSIGN_UNLIMITED_ATTEMPTS) { + $cell2content = get_string('currentattempt', 'assign', $currentattempt); + } else { + $cell2content = get_string('currentattemptof', 'assign', + array('attemptnumber' => $currentattempt, 'maxattempts' => $maxattempts)); + } + + $this->add_table_row_tuple($t, $cell1content, $cell2content); + } + + $cell1content = get_string('submissionstatus', 'assign'); + $cell2attributes = []; + if (!$status->teamsubmissionenabled) { + if ($status->submission && $status->submission->status != ASSIGN_SUBMISSION_STATUS_NEW) { + $cell2content = get_string('submissionstatus_' . $status->submission->status, 'assign'); + $cell2attributes = array('class' => 'submissionstatus' . $status->submission->status); + } else { + if (!$status->submissionsenabled) { + $cell2content = get_string('noonlinesubmissions', 'assign'); + } else { + $cell2content = get_string('noattempt', 'assign'); + } + } + } else { + $group = $status->submissiongroup; + if (!$group && $status->preventsubmissionnotingroup) { + $cell2content = get_string('nosubmission', 'assign'); + } else if ($status->teamsubmission && $status->teamsubmission->status != ASSIGN_SUBMISSION_STATUS_NEW) { + $teamstatus = $status->teamsubmission->status; + $cell2content = get_string('submissionstatus_' . $teamstatus, 'assign'); + + $members = $status->submissiongroupmemberswhoneedtosubmit; + $userslist = array(); + foreach ($members as $member) { + $urlparams = array('id' => $member->id, 'course'=>$status->courseid); + $url = new \moodle_url('/user/view.php', $urlparams); + if ($status->view == assign_submission_status::GRADER_VIEW && $status->blindmarking) { + $userslist[] = $member->alias; + } else { + $fullname = fullname($member, $status->canviewfullnames); + $userslist[] = $this->output->action_link($url, $fullname); + } + } + if (count($userslist) > 0) { + $userstr = join(', ', $userslist); + $formatteduserstr = get_string('userswhoneedtosubmit', 'assign', $userstr); + $cell2content .= $this->output->container($formatteduserstr); + } + + $cell2attributes = array('class' => 'submissionstatus' . $status->teamsubmission->status); + } else { + if (!$status->submissionsenabled) { + $cell2content = get_string('noonlinesubmissions', 'assign'); + } else { + $cell2content = get_string('nosubmission', 'assign'); + } + } + } + + $this->add_table_row_tuple($t, $cell1content, $cell2content, [], $cell2attributes); + + // Is locked? + if ($status->locked) { + $cell1content = ''; + $cell2content = get_string('submissionslocked', 'assign'); + $cell2attributes = array('class' => 'submissionlocked'); + $this->add_table_row_tuple($t, $cell1content, $cell2content, [], $cell2attributes); + } + + // Grading status. + $cell1content = get_string('gradingstatus', 'assign'); + if ($status->gradingstatus == ASSIGN_GRADING_STATUS_GRADED || + $status->gradingstatus == ASSIGN_GRADING_STATUS_NOT_GRADED) { + $cell2content = get_string($status->gradingstatus, 'assign'); + } else { + $gradingstatus = 'markingworkflowstate' . $status->gradingstatus; + $cell2content = get_string($gradingstatus, 'assign'); + } + if ($status->gradingstatus == ASSIGN_GRADING_STATUS_GRADED || + $status->gradingstatus == ASSIGN_MARKING_WORKFLOW_STATE_RELEASED) { + $cell2attributes = array('class' => 'submissiongraded'); + } else { + $cell2attributes = array('class' => 'submissionnotgraded'); + } + $this->add_table_row_tuple($t, $cell1content, $cell2content, [], $cell2attributes); + + $submission = $status->teamsubmission ? $status->teamsubmission : $status->submission; + $duedate = $status->duedate; + if ($duedate > 0) { + if ($status->view == assign_submission_status::GRADER_VIEW) { + if ($status->cutoffdate) { + // Cut off date. + $cell1content = get_string('cutoffdate', 'assign'); + $cell2content = userdate($status->cutoffdate); + $this->add_table_row_tuple($t, $cell1content, $cell2content); + } + } + + if ($status->extensionduedate) { + // Extension date. + $cell1content = get_string('extensionduedate', 'assign'); + $cell2content = userdate($status->extensionduedate); + $this->add_table_row_tuple($t, $cell1content, $cell2content); + $duedate = $status->extensionduedate; + } + + // Time remaining. + $cell1content = get_string('timeremaining', 'assign'); + $cell2attributes = []; + if ($duedate - $time <= 0) { + if (!$submission || + $submission->status != ASSIGN_SUBMISSION_STATUS_SUBMITTED) { + if ($status->submissionsenabled) { + $cell2content = get_string('overdue', 'assign', format_time($time - $duedate)); + $cell2attributes = array('class' => 'overdue'); + } else { + $cell2content = get_string('duedatereached', 'assign'); + } + } else { + if ($submission->timemodified > $duedate) { + $cell2content = get_string('submittedlate', + 'assign', + format_time($submission->timemodified - $duedate)); + $cell2attributes = array('class' => 'latesubmission'); + } else { + $cell2content = get_string('submittedearly', + 'assign', + format_time($submission->timemodified - $duedate)); + $cell2attributes = array('class' => 'earlysubmission'); + } + } + } else { + $cell2content = format_time($duedate - $time); + } + $this->add_table_row_tuple($t, $cell1content, $cell2content, [], $cell2attributes); + } + + // Show graders whether this submission is editable by students. + if ($status->view == assign_submission_status::GRADER_VIEW) { + $cell1content = get_string('editingstatus', 'assign'); + if ($status->canedit) { + $cell2content = get_string('submissioneditable', 'assign'); + $cell2attributes = array('class' => 'submissioneditable'); + } else { + $cell2content = get_string('submissionnoteditable', 'assign'); + $cell2attributes = array('class' => 'submissionnoteditable'); + } + $this->add_table_row_tuple($t, $cell1content, $cell2content, [], $cell2attributes); + } + + // Grading criteria preview. + if (!empty($status->gradingcontrollerpreview)) { + $cell1content = get_string('gradingmethodpreview', 'assign'); + $cell2content = $status->gradingcontrollerpreview; + $this->add_table_row_tuple($t, $cell1content, $cell2content, [], $cell2attributes); + } + + // Last modified. + if ($submission) { + $cell1content = get_string('timemodified', 'assign'); + + if ($submission->status != ASSIGN_SUBMISSION_STATUS_NEW) { + $cell2content = userdate($submission->timemodified); + } else { + $cell2content = "-"; + } + + $this->add_table_row_tuple($t, $cell1content, $cell2content); + + if (!$status->teamsubmission || $status->submissiongroup != false || !$status->preventsubmissionnotingroup) { + foreach ($status->submissionplugins as $plugin) { + $pluginshowsummary = !$plugin->is_empty($submission) || !$plugin->allow_submissions(); + if ($plugin->is_enabled() && + $plugin->is_visible() && + $plugin->has_user_summary() && + $pluginshowsummary + ) { + + $cell1content = $plugin->get_name(); + $displaymode = \assign_submission_plugin_submission::SUMMARY; + $pluginsubmission = new \assign_submission_plugin_submission($plugin, + $submission, + $displaymode, + $status->coursemoduleid, + $status->returnaction, + $status->returnparams); + $cell2content = $this->render($pluginsubmission); + $this->add_table_row_tuple($t, $cell1content, $cell2content); + } + } + } + } + + $o .= $warningmsg; + $o .= \html_writer::table($t); + $o .= $this->output->box_end(); + + // Links. + if ($status->view == assign_submission_status::STUDENT_VIEW) { + if ($status->canedit) { + if (!$submission || $submission->status == ASSIGN_SUBMISSION_STATUS_NEW) { + $o .= $this->output->box_start('generalbox submissionaction'); + $urlparams = array('id' => $status->coursemoduleid, 'action' => 'editsubmission'); + $o .= $this->output->single_button(new \moodle_url('/mod/assign/view.php', $urlparams), + get_string('addsubmission', 'assign'), 'get'); + $o .= $this->output->box_start('boxaligncenter submithelp'); + $o .= get_string('addsubmission_help', 'assign'); + $o .= $this->output->box_end(); + $o .= $this->output->box_end(); + } else if ($submission->status == ASSIGN_SUBMISSION_STATUS_REOPENED) { + $o .= $this->output->box_start('generalbox submissionaction'); + $urlparams = array('id' => $status->coursemoduleid, + 'action' => 'editprevioussubmission', + 'sesskey'=>sesskey()); + $o .= $this->output->single_button(new \moodle_url('/mod/assign/view.php', $urlparams), + get_string('addnewattemptfromprevious', 'assign'), 'get'); + $o .= $this->output->box_start('boxaligncenter submithelp'); + $o .= get_string('addnewattemptfromprevious_help', 'assign'); + $o .= $this->output->box_end(); + $o .= $this->output->box_end(); + $o .= $this->output->box_start('generalbox submissionaction'); + $urlparams = array('id' => $status->coursemoduleid, 'action' => 'editsubmission'); + $o .= $this->output->single_button(new \moodle_url('/mod/assign/view.php', $urlparams), + get_string('addnewattempt', 'assign'), 'get'); + $o .= $this->output->box_start('boxaligncenter submithelp'); + $o .= get_string('addnewattempt_help', 'assign'); + $o .= $this->output->box_end(); + $o .= $this->output->box_end(); + } else { + $o .= $this->output->box_start('generalbox submissionaction'); + $urlparams = array('id' => $status->coursemoduleid, 'action' => 'editsubmission'); + $o .= $this->output->single_button(new \moodle_url('/mod/assign/view.php', $urlparams), + get_string('editsubmission', 'assign'), 'get'); + $urlparams = array('id' => $status->coursemoduleid, 'action' => 'removesubmissionconfirm'); + $o .= $this->output->single_button(new \moodle_url('/mod/assign/view.php', $urlparams), + get_string('removesubmission', 'assign'), 'get'); + $o .= $this->output->box_start('boxaligncenter submithelp'); + $o .= get_string('editsubmission_help', 'assign'); + $o .= $this->output->box_end(); + $o .= $this->output->box_end(); + } + } + + if ($status->cansubmit) { + $urlparams = array('id' => $status->coursemoduleid, 'action'=>'submit'); + $o .= $this->output->box_start('generalbox submissionaction'); + $o .= $this->output->single_button(new \moodle_url('/mod/assign/view.php', $urlparams), + get_string('submitassignment', 'assign'), 'get'); + $o .= $this->output->box_start('boxaligncenter submithelp'); + $o .= get_string('submitassignment_help', 'assign'); + $o .= $this->output->box_end(); + $o .= $this->output->box_end(); + } + } + + $o .= $this->output->container_end(); + return $o; + } + + /** + * Output the attempt history chooser for this assignment + * + * @param \assign_attempt_history_chooser $history + * @return string + */ + public function render_assign_attempt_history_chooser(\assign_attempt_history_chooser $history) { + $o = ''; + + $context = $history->export_for_template($this); + $o .= $this->render_from_template('mod_assign/attempt_history_chooser', $context); + + return $o; + } + + /** + * Output the attempt history for this assignment + * + * @param \assign_attempt_history $history + * @return string + */ + public function render_assign_attempt_history(\assign_attempt_history $history) { + $o = ''; + + // Don't show the last one because it is the current submission. + array_pop($history->submissions); + + // Show newest to oldest. + $history->submissions = array_reverse($history->submissions); + + if (empty($history->submissions)) { + return ''; + } + + $containerid = 'attempthistory' . uniqid(); + $o .= $this->output->heading(get_string('attempthistory', 'assign'), 3); + $o .= $this->box_start('attempthistory', $containerid); + + foreach ($history->submissions as $i => $submission) { + $grade = null; + foreach ($history->grades as $onegrade) { + if ($onegrade->attemptnumber == $submission->attemptnumber) { + if ($onegrade->grade != ASSIGN_GRADE_NOT_SET) { + $grade = $onegrade; + } + break; + } + } + + if ($submission) { + $submissionsummary = userdate($submission->timemodified); + } else { + $submissionsummary = get_string('nosubmission', 'assign'); + } + + $attemptsummaryparams = array('attemptnumber'=>$submission->attemptnumber+1, + 'submissionsummary'=>$submissionsummary); + $o .= $this->heading(get_string('attemptheading', 'assign', $attemptsummaryparams), 4); + + $t = new \html_table(); + + if ($submission) { + $cell1content = get_string('submissionstatus', 'assign'); + $cell2content = get_string('submissionstatus_' . $submission->status, 'assign'); + $this->add_table_row_tuple($t, $cell1content, $cell2content); + + foreach ($history->submissionplugins as $plugin) { + $pluginshowsummary = !$plugin->is_empty($submission) || !$plugin->allow_submissions(); + if ($plugin->is_enabled() && + $plugin->is_visible() && + $plugin->has_user_summary() && + $pluginshowsummary) { + + $cell1content = $plugin->get_name(); + $pluginsubmission = new \assign_submission_plugin_submission($plugin, + $submission, + \assign_submission_plugin_submission::SUMMARY, + $history->coursemoduleid, + $history->returnaction, + $history->returnparams); + $cell2content = $this->render($pluginsubmission); + $this->add_table_row_tuple($t, $cell1content, $cell2content); + } + } + } + + if ($grade) { + // Heading 'feedback'. + $title = get_string('feedback', 'assign', $i); + $title .= $this->output->spacer(array('width'=>10)); + if ($history->cangrade) { + // Edit previous feedback. + $returnparams = http_build_query($history->returnparams); + $urlparams = array('id' => $history->coursemoduleid, + 'rownum'=>$history->rownum, + 'useridlistid'=>$history->useridlistid, + 'attemptnumber'=>$grade->attemptnumber, + 'action'=>'grade', + 'returnaction'=>$history->returnaction, + 'returnparams'=>$returnparams); + $url = new \moodle_url('/mod/assign/view.php', $urlparams); + $icon = new \pix_icon('gradefeedback', + get_string('editattemptfeedback', 'assign', $grade->attemptnumber+1), + 'mod_assign'); + $title .= $this->output->action_icon($url, $icon); + } + $cell = new \html_table_cell($title); + $cell->attributes['class'] = 'feedbacktitle'; + $cell->colspan = 2; + $t->data[] = new \html_table_row(array($cell)); + + // Grade. + $cell1content = get_string('gradenoun'); + $cell2content = $grade->gradefordisplay; + $this->add_table_row_tuple($t, $cell1content, $cell2content); + + // Graded on. + $cell1content = get_string('gradedon', 'assign'); + $cell2content = userdate($grade->timemodified); + $this->add_table_row_tuple($t, $cell1content, $cell2content); + + // Graded by set to a real user. Not set can be empty or -1. + if (!empty($grade->grader) && is_object($grade->grader)) { + $cell1content = get_string('gradedby', 'assign'); + $cell2content = $this->output->user_picture($grade->grader) . + $this->output->spacer(array('width' => 30)) . fullname($grade->grader); + $this->add_table_row_tuple($t, $cell1content, $cell2content); + } + + // Feedback from plugins. + foreach ($history->feedbackplugins as $plugin) { + if ($plugin->is_enabled() && + $plugin->is_visible() && + $plugin->has_user_summary() && + !$plugin->is_empty($grade)) { + + $pluginfeedback = new \assign_feedback_plugin_feedback( + $plugin, $grade, \assign_feedback_plugin_feedback::SUMMARY, $history->coursemoduleid, + $history->returnaction, $history->returnparams + ); + + $cell1content = $plugin->get_name(); + $cell2content = $this->render($pluginfeedback); + $this->add_table_row_tuple($t, $cell1content, $cell2content); + } + + } + + } + + $o .= \html_writer::table($t); + } + $o .= $this->box_end(); + + $this->page->requires->yui_module('moodle-mod_assign-history', 'Y.one("#' . $containerid . '").history'); + + return $o; + } + + /** + * Render a submission plugin submission + * + * @param \assign_submission_plugin_submission $submissionplugin + * @return string + */ + public function render_assign_submission_plugin_submission(\assign_submission_plugin_submission $submissionplugin) { + $o = ''; + + if ($submissionplugin->view == \assign_submission_plugin_submission::SUMMARY) { + $showviewlink = false; + $summary = $submissionplugin->plugin->view_summary($submissionplugin->submission, + $showviewlink); + + $classsuffix = $submissionplugin->plugin->get_subtype() . + '_' . + $submissionplugin->plugin->get_type() . + '_' . + $submissionplugin->submission->id; + + $o .= $this->output->box_start('boxaligncenter plugincontentsummary summary_' . $classsuffix); + + $link = ''; + if ($showviewlink) { + $previewstr = get_string('viewsubmission', 'assign'); + $icon = $this->output->pix_icon('t/preview', $previewstr); + + $expandstr = get_string('viewfull', 'assign'); + $expandicon = $this->output->pix_icon('t/switch_plus', $expandstr); + $options = array( + 'class' => 'expandsummaryicon expand_' . $classsuffix, + 'aria-label' => $expandstr, + 'role' => 'button', + 'aria-expanded' => 'false' + ); + $o .= \html_writer::link('', $expandicon, $options); + + $jsparams = array($submissionplugin->plugin->get_subtype(), + $submissionplugin->plugin->get_type(), + $submissionplugin->submission->id); + + $this->page->requires->js_init_call('M.mod_assign.init_plugin_summary', $jsparams); + + $action = 'viewplugin' . $submissionplugin->plugin->get_subtype(); + $returnparams = http_build_query($submissionplugin->returnparams); + $link .= ''; + + $link .= $this->output->spacer(array('width'=>15)); + } + + $o .= $link . $summary; + $o .= $this->output->box_end(); + if ($showviewlink) { + $o .= $this->output->box_start('boxaligncenter hidefull full_' . $classsuffix); + $collapsestr = get_string('viewsummary', 'assign'); + $options = array( + 'class' => 'expandsummaryicon contract_' . $classsuffix, + 'aria-label' => $collapsestr, + 'role' => 'button', + 'aria-expanded' => 'true' + ); + $collapseicon = $this->output->pix_icon('t/switch_minus', $collapsestr); + $o .= \html_writer::link('', $collapseicon, $options); + + $o .= $submissionplugin->plugin->view($submissionplugin->submission); + $o .= $this->output->box_end(); + } + } else if ($submissionplugin->view == \assign_submission_plugin_submission::FULL) { + $o .= $this->output->box_start('boxaligncenter submissionfull'); + $o .= $submissionplugin->plugin->view($submissionplugin->submission); + $o .= $this->output->box_end(); + } + + return $o; + } + + /** + * Render the grading table. + * + * @param \assign_grading_table $table + * @return string + */ + public function render_assign_grading_table(\assign_grading_table $table) { + $o = ''; + $o .= $this->output->box_start('boxaligncenter gradingtable'); + + $this->page->requires->js_init_call('M.mod_assign.init_grading_table', array()); + $this->page->requires->string_for_js('nousersselected', 'assign'); + $this->page->requires->string_for_js('batchoperationconfirmgrantextension', 'assign'); + $this->page->requires->string_for_js('batchoperationconfirmlock', 'assign'); + $this->page->requires->string_for_js('batchoperationconfirmremovesubmission', 'assign'); + $this->page->requires->string_for_js('batchoperationconfirmreverttodraft', 'assign'); + $this->page->requires->string_for_js('batchoperationconfirmunlock', 'assign'); + $this->page->requires->string_for_js('batchoperationconfirmaddattempt', 'assign'); + $this->page->requires->string_for_js('batchoperationconfirmdownloadselected', 'assign'); + $this->page->requires->string_for_js('batchoperationconfirmsetmarkingworkflowstate', 'assign'); + $this->page->requires->string_for_js('batchoperationconfirmsetmarkingallocation', 'assign'); + $this->page->requires->string_for_js('editaction', 'assign'); + foreach ($table->plugingradingbatchoperations as $plugin => $operations) { + foreach ($operations as $operation => $description) { + $this->page->requires->string_for_js('batchoperationconfirm' . $operation, + 'assignfeedback_' . $plugin); + } + } + $o .= $this->flexible_table($table, $table->get_rows_per_page(), true); + $o .= $this->output->box_end(); + + return $o; + } + + /** + * Render a feedback plugin feedback + * + * @param \assign_feedback_plugin_feedback $feedbackplugin + * @return string + */ + public function render_assign_feedback_plugin_feedback(\assign_feedback_plugin_feedback $feedbackplugin) { + $o = ''; + + if ($feedbackplugin->view == \assign_feedback_plugin_feedback::SUMMARY) { + $showviewlink = false; + $summary = $feedbackplugin->plugin->view_summary($feedbackplugin->grade, $showviewlink); + + $classsuffix = $feedbackplugin->plugin->get_subtype() . + '_' . + $feedbackplugin->plugin->get_type() . + '_' . + $feedbackplugin->grade->id; + $o .= $this->output->box_start('boxaligncenter plugincontentsummary summary_' . $classsuffix); + + $link = ''; + if ($showviewlink) { + $previewstr = get_string('viewfeedback', 'assign'); + $icon = $this->output->pix_icon('t/preview', $previewstr); + + $expandstr = get_string('viewfull', 'assign'); + $expandicon = $this->output->pix_icon('t/switch_plus', $expandstr); + $options = array( + 'class' => 'expandsummaryicon expand_' . $classsuffix, + 'aria-label' => $expandstr, + 'role' => 'button', + 'aria-expanded' => 'false' + ); + $o .= \html_writer::link('', $expandicon, $options); + + $jsparams = array($feedbackplugin->plugin->get_subtype(), + $feedbackplugin->plugin->get_type(), + $feedbackplugin->grade->id); + $this->page->requires->js_init_call('M.mod_assign.init_plugin_summary', $jsparams); + + $urlparams = array('id' => $feedbackplugin->coursemoduleid, + 'gid'=>$feedbackplugin->grade->id, + 'plugin'=>$feedbackplugin->plugin->get_type(), + 'action'=>'viewplugin' . $feedbackplugin->plugin->get_subtype(), + 'returnaction'=>$feedbackplugin->returnaction, + 'returnparams'=>http_build_query($feedbackplugin->returnparams)); + $url = new \moodle_url('/mod/assign/view.php', $urlparams); + $link .= ''; + + $link .= $this->output->spacer(array('width'=>15)); + } + + $o .= $link . $summary; + $o .= $this->output->box_end(); + if ($showviewlink) { + $o .= $this->output->box_start('boxaligncenter hidefull full_' . $classsuffix); + $collapsestr = get_string('viewsummary', 'assign'); + $options = array( + 'class' => 'expandsummaryicon contract_' . $classsuffix, + 'aria-label' => $collapsestr, + 'role' => 'button', + 'aria-expanded' => 'true' + ); + $collapseicon = $this->output->pix_icon('t/switch_minus', $collapsestr); + $o .= \html_writer::link('', $collapseicon, $options); + + $o .= $feedbackplugin->plugin->view($feedbackplugin->grade); + $o .= $this->output->box_end(); + } + } else if ($feedbackplugin->view == \assign_feedback_plugin_feedback::FULL) { + $o .= $this->output->box_start('boxaligncenter feedbackfull'); + $o .= $feedbackplugin->plugin->view($feedbackplugin->grade); + $o .= $this->output->box_end(); + } + + return $o; + } + + /** + * Render a course index summary + * + * @param \assign_course_index_summary $indexsummary + * @return string + */ + public function render_assign_course_index_summary(\assign_course_index_summary $indexsummary) { + $o = ''; + + $strplural = get_string('modulenameplural', 'assign'); + $strsectionname = $indexsummary->courseformatname; + $strduedate = get_string('duedate', 'assign'); + $strsubmission = get_string('submission', 'assign'); + $strgrade = get_string('gradenoun'); + + $table = new \html_table(); + if ($indexsummary->usesections) { + $table->head = array ($strsectionname, $strplural, $strduedate, $strsubmission, $strgrade); + $table->align = array ('left', 'left', 'center', 'right', 'right'); + } else { + $table->head = array ($strplural, $strduedate, $strsubmission, $strgrade); + $table->align = array ('left', 'left', 'center', 'right'); + } + $table->data = array(); + + $currentsection = ''; + foreach ($indexsummary->assignments as $info) { + $params = array('id' => $info['cmid']); + $link = \html_writer::link(new \moodle_url('/mod/assign/view.php', $params), + $info['cmname']); + $due = $info['timedue'] ? userdate($info['timedue']) : '-'; + + $printsection = ''; + if ($indexsummary->usesections) { + if ($info['sectionname'] !== $currentsection) { + if ($info['sectionname']) { + $printsection = $info['sectionname']; + } + if ($currentsection !== '') { + $table->data[] = 'hr'; + } + $currentsection = $info['sectionname']; + } + } + + if ($indexsummary->usesections) { + $row = array($printsection, $link, $due, $info['submissioninfo'], $info['gradeinfo']); + } else { + $row = array($link, $due, $info['submissioninfo'], $info['gradeinfo']); + } + $table->data[] = $row; + } + + $o .= \html_writer::table($table); + + return $o; + } + + + + /** + * Internal function - creates htmls structure suitable for YUI tree. + * + * @param \assign_files $tree + * @param array $dir + * @return string + */ + protected function htmllize_tree(\assign_files $tree, $dir) { + global $CFG; + $yuiconfig = array(); + $yuiconfig['type'] = 'html'; + + if (empty($dir['subdirs']) and empty($dir['files'])) { + return ''; + } + + $result = ''; + + return $result; + } + + /** + * Helper method dealing with the fact we can not just fetch the output of flexible_table + * + * @param \flexible_table $table The table to render + * @param int $rowsperpage How many assignments to render in a page + * @param bool $displaylinks - Whether to render links in the table + * (e.g. downloads would not enable this) + * @return string HTML + */ + protected function flexible_table(\flexible_table $table, $rowsperpage, $displaylinks) { + + $o = ''; + ob_start(); + $table->out($rowsperpage, $displaylinks); + $o = ob_get_contents(); + ob_end_clean(); + + return $o; + } + + /** + * Helper method dealing with the fact we can not just fetch the output of moodleforms + * + * @param \moodleform $mform + * @return string HTML + */ + protected function moodleform(\moodleform $mform) { + + $o = ''; + ob_start(); + $mform->display(); + $o = ob_get_contents(); + ob_end_clean(); + + return $o; + } + + /** + * Defer to template. + * + * @param grading_app $app - All the data to render the grading app. + */ + public function render_grading_app(grading_app $app) { + $context = $app->export_for_template($this); + return $this->render_from_template('mod_assign/grading_app', $context); + } + +} diff --git a/mod/assign/db/renamedclasses.php b/mod/assign/db/renamedclasses.php new file mode 100644 index 00000000000..dca2b289f9f --- /dev/null +++ b/mod/assign/db/renamedclasses.php @@ -0,0 +1,32 @@ +. + +/** + * This file contains mappings for classes that have been renamed. + * + * @package mod_assign + * @copyright 2021 Catalyst IT Australia Pty Ltd + * @author Cameron Ball + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +$renamedclasses = [ + // Since Moodle 4.0. + 'assign_header' => 'mod_assign\output\assign_header', + 'assign_submission_status' => 'mod_assign\output\assign_submission_status' +]; diff --git a/mod/assign/feedback/file/importziplib.php b/mod/assign/feedback/file/importziplib.php index 3cbe9f79c1e..3b61b15e119 100644 --- a/mod/assign/feedback/file/importziplib.php +++ b/mod/assign/feedback/file/importziplib.php @@ -25,6 +25,8 @@ defined('MOODLE_INTERNAL') || die(); +use mod_assign\output\assign_header; + /** * library class for importing feedback files from a zip * diff --git a/mod/assign/feedback/file/locallib.php b/mod/assign/feedback/file/locallib.php index dd65b23903d..30c2821116b 100644 --- a/mod/assign/feedback/file/locallib.php +++ b/mod/assign/feedback/file/locallib.php @@ -25,6 +25,8 @@ defined('MOODLE_INTERNAL') || die(); +use \mod_assign\output\assign_header; + // File areas for file feedback assignment. define('ASSIGNFEEDBACK_FILE_FILEAREA', 'feedback_files'); define('ASSIGNFEEDBACK_FILE_BATCH_FILEAREA', 'feedback_files_batch'); diff --git a/mod/assign/feedback/offline/locallib.php b/mod/assign/feedback/offline/locallib.php index efbf3b34d98..c93246147ee 100644 --- a/mod/assign/feedback/offline/locallib.php +++ b/mod/assign/feedback/offline/locallib.php @@ -25,6 +25,8 @@ defined('MOODLE_INTERNAL') || die(); +use \mod_assign\output\assign_header; + require_once($CFG->dirroot.'/grade/grading/lib.php'); /** diff --git a/mod/assign/locallib.php b/mod/assign/locallib.php index 05c71bcbe5a..81807ca172b 100644 --- a/mod/assign/locallib.php +++ b/mod/assign/locallib.php @@ -92,6 +92,8 @@ require_once($CFG->dirroot . '/mod/assign/gradingtable.php'); require_once($CFG->libdir . '/portfolio/caller.php'); use \mod_assign\output\grading_app; +use \mod_assign\output\assign_header; +use \mod_assign\output\assign_submission_status; /** * Standard base class for mod_assign (assignment types). diff --git a/mod/assign/renderable.php b/mod/assign/renderable.php index 295fc3c93f0..836686c0fd8 100644 --- a/mod/assign/renderable.php +++ b/mod/assign/renderable.php @@ -22,6 +22,8 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ +use \mod_assign\output\assign_submission_status; + defined('MOODLE_INTERNAL') || die(); /** @@ -271,7 +273,7 @@ class assign_submission_plugin_submission implements renderable { */ class assign_feedback_status implements renderable { - /** @var stding $gradefordisplay the student grade rendered into a format suitable for display */ + /** @var string $gradefordisplay the student grade rendered into a format suitable for display */ public $gradefordisplay = ''; /** @var mixed the graded date (may be null) */ public $gradeddate = 0; @@ -323,176 +325,6 @@ class assign_feedback_status implements renderable { } } -/** - * Renderable submission status - * @package mod_assign - * @copyright 2012 NetSpot {@link http://www.netspot.com.au} - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class assign_submission_status implements renderable { - /** @var int STUDENT_VIEW */ - const STUDENT_VIEW = 10; - /** @var int GRADER_VIEW */ - const GRADER_VIEW = 20; - - /** @var int allowsubmissionsfromdate */ - public $allowsubmissionsfromdate = 0; - /** @var bool alwaysshowdescription */ - public $alwaysshowdescription = false; - /** @var stdClass the submission info (may be null) */ - public $submission = null; - /** @var boolean teamsubmissionenabled - true or false */ - public $teamsubmissionenabled = false; - /** @var stdClass teamsubmission the team submission info (may be null) */ - public $teamsubmission = null; - /** @var stdClass submissiongroup the submission group info (may be null) */ - public $submissiongroup = null; - /** @var array submissiongroupmemberswhoneedtosubmit list of users who still need to submit */ - public $submissiongroupmemberswhoneedtosubmit = array(); - /** @var bool submissionsenabled */ - public $submissionsenabled = false; - /** @var bool locked */ - public $locked = false; - /** @var bool graded */ - public $graded = false; - /** @var int duedate */ - public $duedate = 0; - /** @var int cutoffdate */ - public $cutoffdate = 0; - /** @var array submissionplugins - the list of submission plugins */ - public $submissionplugins = array(); - /** @var string returnaction */ - public $returnaction = ''; - /** @var string returnparams */ - public $returnparams = array(); - /** @var int courseid */ - public $courseid = 0; - /** @var int coursemoduleid */ - public $coursemoduleid = 0; - /** @var int the view (STUDENT_VIEW OR GRADER_VIEW) */ - public $view = self::STUDENT_VIEW; - /** @var bool canviewfullnames */ - public $canviewfullnames = false; - /** @var bool canedit */ - public $canedit = false; - /** @var bool cansubmit */ - public $cansubmit = false; - /** @var int extensionduedate */ - public $extensionduedate = 0; - /** @var context context */ - public $context = 0; - /** @var bool blindmarking - Should we hide student identities from graders? */ - public $blindmarking = false; - /** @var string gradingcontrollerpreview */ - public $gradingcontrollerpreview = ''; - /** @var string attemptreopenmethod */ - public $attemptreopenmethod = 'none'; - /** @var int maxattempts */ - public $maxattempts = -1; - /** @var string gradingstatus */ - public $gradingstatus = ''; - /** @var bool preventsubmissionnotingroup */ - public $preventsubmissionnotingroup = 0; - /** @var array usergroups */ - public $usergroups = array(); - - - /** - * Constructor - * - * @param int $allowsubmissionsfromdate - * @param bool $alwaysshowdescription - * @param stdClass $submission - * @param bool $teamsubmissionenabled - * @param stdClass $teamsubmission - * @param int $submissiongroup - * @param array $submissiongroupmemberswhoneedtosubmit - * @param bool $submissionsenabled - * @param bool $locked - * @param bool $graded - * @param int $duedate - * @param int $cutoffdate - * @param array $submissionplugins - * @param string $returnaction - * @param array $returnparams - * @param int $coursemoduleid - * @param int $courseid - * @param string $view - * @param bool $canedit - * @param bool $cansubmit - * @param bool $canviewfullnames - * @param int $extensionduedate - Any extension to the due date granted for this user - * @param context $context - Any extension to the due date granted for this user - * @param bool $blindmarking - Should we hide student identities from graders? - * @param string $gradingcontrollerpreview - * @param string $attemptreopenmethod - The method of reopening student attempts. - * @param int $maxattempts - How many attempts can a student make? - * @param string $gradingstatus - The submission status (ie. Graded, Not Released etc). - * @param bool $preventsubmissionnotingroup - Prevent submission if user is not in a group - * @param array $usergroups - Array containing all groups the user is assigned to - */ - public function __construct($allowsubmissionsfromdate, - $alwaysshowdescription, - $submission, - $teamsubmissionenabled, - $teamsubmission, - $submissiongroup, - $submissiongroupmemberswhoneedtosubmit, - $submissionsenabled, - $locked, - $graded, - $duedate, - $cutoffdate, - $submissionplugins, - $returnaction, - $returnparams, - $coursemoduleid, - $courseid, - $view, - $canedit, - $cansubmit, - $canviewfullnames, - $extensionduedate, - $context, - $blindmarking, - $gradingcontrollerpreview, - $attemptreopenmethod, - $maxattempts, - $gradingstatus, - $preventsubmissionnotingroup, - $usergroups) { - $this->allowsubmissionsfromdate = $allowsubmissionsfromdate; - $this->alwaysshowdescription = $alwaysshowdescription; - $this->submission = $submission; - $this->teamsubmissionenabled = $teamsubmissionenabled; - $this->teamsubmission = $teamsubmission; - $this->submissiongroup = $submissiongroup; - $this->submissiongroupmemberswhoneedtosubmit = $submissiongroupmemberswhoneedtosubmit; - $this->submissionsenabled = $submissionsenabled; - $this->locked = $locked; - $this->graded = $graded; - $this->duedate = $duedate; - $this->cutoffdate = $cutoffdate; - $this->submissionplugins = $submissionplugins; - $this->returnaction = $returnaction; - $this->returnparams = $returnparams; - $this->coursemoduleid = $coursemoduleid; - $this->courseid = $courseid; - $this->view = $view; - $this->canedit = $canedit; - $this->cansubmit = $cansubmit; - $this->canviewfullnames = $canviewfullnames; - $this->extensionduedate = $extensionduedate; - $this->context = $context; - $this->blindmarking = $blindmarking; - $this->gradingcontrollerpreview = $gradingcontrollerpreview; - $this->attemptreopenmethod = $attemptreopenmethod; - $this->maxattempts = $maxattempts; - $this->gradingstatus = $gradingstatus; - $this->preventsubmissionnotingroup = $preventsubmissionnotingroup; - $this->usergroups = $usergroups; - } -} /** * Renderable submission status * @package mod_assign @@ -650,59 +482,6 @@ class assign_attempt_history_chooser implements renderable, templatable { } } -/** - * Renderable header - * @package mod_assign - * @copyright 2012 NetSpot {@link http://www.netspot.com.au} - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class assign_header implements renderable { - /** @var stdClass the assign record */ - public $assign = null; - /** @var mixed context|null the context record */ - public $context = null; - /** @var bool $showintro - show or hide the intro */ - public $showintro = false; - /** @var int coursemoduleid - The course module id */ - public $coursemoduleid = 0; - /** @var string $subpage optional subpage (extra level in the breadcrumbs) */ - public $subpage = ''; - /** @var string $preface optional preface (text to show before the heading) */ - public $preface = ''; - /** @var string $postfix optional postfix (text to show after the intro) */ - public $postfix = ''; - /** @var moodle_url $subpageurl link for the subpage */ - public $subpageurl = null; - - /** - * Constructor - * - * @param stdClass $assign - the assign database record - * @param mixed $context context|null the course module context - * @param bool $showintro - show or hide the intro - * @param int $coursemoduleid - the course module id - * @param string $subpage - an optional sub page in the navigation - * @param string $preface - an optional preface to show before the heading - */ - public function __construct(stdClass $assign, - $context, - $showintro, - $coursemoduleid, - $subpage='', - $preface='', - $postfix='', - moodle_url $subpageurl = null) { - $this->assign = $assign; - $this->context = $context; - $this->showintro = $showintro; - $this->coursemoduleid = $coursemoduleid; - $this->subpage = $subpage; - $this->preface = $preface; - $this->postfix = $postfix; - $this->subpageurl = $subpageurl; - } -} - /** * Renderable header related to an individual subplugin * @package mod_assign diff --git a/mod/assign/renderer.php b/mod/assign/renderer.php index 950983a2df8..aac1178a403 100644 --- a/mod/assign/renderer.php +++ b/mod/assign/renderer.php @@ -15,8 +15,10 @@ // along with Moodle. If not, see . /** - * This file contains a renderer for the assignment class + * Legacy file to avoid exceptions when scripts require it. + * Please use classes from mod/assign/classes/output instead. * + * @deprecated since Moodle 4.0 - please do not include this file anymore. * @package mod_assign * @copyright 2012 NetSpot {@link http://www.netspot.com.au} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later @@ -24,1459 +26,4 @@ defined('MOODLE_INTERNAL') || die(); -require_once($CFG->dirroot . '/mod/assign/locallib.php'); - -use \mod_assign\output\grading_app; - -/** - * A custom renderer class that extends the plugin_renderer_base and is used by the assign module. - * - * @package mod_assign - * @copyright 2012 NetSpot {@link http://www.netspot.com.au} - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class mod_assign_renderer extends plugin_renderer_base { - - /** - * Rendering assignment files - * - * @param context $context - * @param int $userid - * @param string $filearea - * @param string $component - * @param stdClass $course - * @param stdClass $coursemodule - * @return string - */ - public function assign_files(context $context, $userid, $filearea, $component, $course = null, $coursemodule = null) { - return $this->render(new assign_files($context, $userid, $filearea, $component, $course, $coursemodule)); - } - - /** - * Rendering assignment files - * - * @param assign_files $tree - * @return string - */ - public function render_assign_files(assign_files $tree) { - $this->htmlid = html_writer::random_id('assign_files_tree'); - $this->page->requires->js_init_call('M.mod_assign.init_tree', array(true, $this->htmlid)); - $html = '
'; - $html .= $this->htmllize_tree($tree, $tree->dir); - $html .= '
'; - - if ($tree->portfolioform) { - $html .= $tree->portfolioform; - } - return $html; - } - - /** - * Utility function to add a row of data to a table with 2 columns where the first column is the table's header. - * Modified the table param and does not return a value. - * - * @param html_table $table The table to append the row of data to - * @param string $first The first column text - * @param string $second The second column text - * @param array $firstattributes The first column attributes (optional) - * @param array $secondattributes The second column attributes (optional) - * @return void - */ - private function add_table_row_tuple(html_table $table, $first, $second, $firstattributes = [], - $secondattributes = []) { - $row = new html_table_row(); - $cell1 = new html_table_cell($first); - $cell1->header = true; - if (!empty($firstattributes)) { - $cell1->attributes = $firstattributes; - } - $cell2 = new html_table_cell($second); - if (!empty($secondattributes)) { - $cell2->attributes = $secondattributes; - } - $row->cells = array($cell1, $cell2); - $table->data[] = $row; - } - - /** - * Render a grading message notification - * @param assign_gradingmessage $result The result to render - * @return string - */ - public function render_assign_gradingmessage(assign_gradingmessage $result) { - $urlparams = array('id' => $result->coursemoduleid, 'action'=>'grading'); - if (!empty($result->page)) { - $urlparams['page'] = $result->page; - } - $url = new moodle_url('/mod/assign/view.php', $urlparams); - $classes = $result->gradingerror ? 'notifyproblem' : 'notifysuccess'; - - $o = ''; - $o .= $this->output->heading($result->heading, 4); - $o .= $this->output->notification($result->message, $classes); - $o .= $this->output->continue_button($url); - return $o; - } - - /** - * Render the generic form - * @param assign_form $form The form to render - * @return string - */ - public function render_assign_form(assign_form $form) { - $o = ''; - if ($form->jsinitfunction) { - $this->page->requires->js_init_call($form->jsinitfunction, array()); - } - $o .= $this->output->box_start('boxaligncenter ' . $form->classname); - $o .= $this->moodleform($form->form); - $o .= $this->output->box_end(); - return $o; - } - - /** - * Render the user summary - * - * @param assign_user_summary $summary The user summary to render - * @return string - */ - public function render_assign_user_summary(assign_user_summary $summary) { - $o = ''; - $supendedclass = ''; - $suspendedicon = ''; - - if (!$summary->user) { - return; - } - - if ($summary->suspendeduser) { - $supendedclass = ' usersuspended'; - $suspendedstring = get_string('userenrolmentsuspended', 'grades'); - $suspendedicon = ' ' . $this->pix_icon('i/enrolmentsuspended', $suspendedstring); - } - $o .= $this->output->container_start('usersummary'); - $o .= $this->output->box_start('boxaligncenter usersummarysection'.$supendedclass); - if ($summary->blindmarking) { - $o .= get_string('hiddenuser', 'assign') . $summary->uniqueidforuser.$suspendedicon; - } else { - $o .= $this->output->user_picture($summary->user); - $o .= $this->output->spacer(array('width'=>30)); - $urlparams = array('id' => $summary->user->id, 'course'=>$summary->courseid); - $url = new moodle_url('/user/view.php', $urlparams); - $fullname = fullname($summary->user, $summary->viewfullnames); - $extrainfo = array(); - foreach ($summary->extrauserfields as $extrafield) { - $extrainfo[] = $summary->user->$extrafield; - } - if (count($extrainfo)) { - $fullname .= ' (' . implode(', ', $extrainfo) . ')'; - } - $fullname .= $suspendedicon; - $o .= $this->output->action_link($url, $fullname); - } - $o .= $this->output->box_end(); - $o .= $this->output->container_end(); - - return $o; - } - - /** - * Render the submit for grading page - * - * @param assign_submit_for_grading_page $page - * @return string - */ - public function render_assign_submit_for_grading_page($page) { - $o = ''; - - $o .= $this->output->container_start('submitforgrading'); - $o .= $this->output->heading(get_string('confirmsubmissionheading', 'assign'), 3); - - $cancelurl = new moodle_url('/mod/assign/view.php', array('id' => $page->coursemoduleid)); - if (count($page->notifications)) { - // At least one of the submission plugins is not ready for submission. - - $o .= $this->output->heading(get_string('submissionnotready', 'assign'), 4); - - foreach ($page->notifications as $notification) { - $o .= $this->output->notification($notification); - } - - $o .= $this->output->continue_button($cancelurl); - } else { - // All submission plugins ready - show the confirmation form. - $o .= $this->moodleform($page->confirmform); - } - $o .= $this->output->container_end(); - - return $o; - } - - /** - * Page is done - render the footer. - * - * @return void - */ - public function render_footer() { - return $this->output->footer(); - } - - /** - * Render the header. - * - * @param assign_header $header - * @return string - */ - public function render_assign_header(assign_header $header) { - global $USER; - - $o = ''; - - if ($header->subpage) { - $this->page->navbar->add($header->subpage, $header->subpageurl); - $args = ['contextname' => $header->context->get_context_name(false, true), 'subpage' => $header->subpage]; - $title = get_string('subpagetitle', 'assign', $args); - } else { - $title = $header->context->get_context_name(false, true); - } - $courseshortname = $header->context->get_course_context()->get_context_name(false, true); - $title = $courseshortname . ': ' . $title; - $heading = format_string($header->assign->name, false, array('context' => $header->context)); - - $this->page->set_title($title); - $this->page->set_heading($this->page->course->fullname); - - $o .= $this->output->header(); - $o .= $this->output->heading($heading); - - // Show the activity information output component. - $modinfo = get_fast_modinfo($header->assign->course); - $cm = $modinfo->get_cm($header->coursemoduleid); - $cmcompletion = \core_completion\cm_completion_details::get_instance($cm, $USER->id); - $activitydates = \core\activity_dates::get_dates_for_module($cm, $USER->id); - $o .= $this->output->activity_information($cm, $cmcompletion, $activitydates); - - if ($header->preface) { - $o .= $header->preface; - } - - if ($header->showintro) { - $o .= $this->output->box_start('generalbox boxaligncenter', 'intro'); - $o .= format_module_intro('assign', $header->assign, $header->coursemoduleid); - $o .= $header->postfix; - $o .= $this->output->box_end(); - } - - return $o; - } - - /** - * Render the header for an individual plugin. - * - * @param assign_plugin_header $header - * @return string - */ - public function render_assign_plugin_header(assign_plugin_header $header) { - $o = $header->plugin->view_header(); - return $o; - } - - /** - * Render a table containing the current status of the grading process. - * - * @param assign_grading_summary $summary - * @return string - */ - public function render_assign_grading_summary(assign_grading_summary $summary) { - // Create a table for the data. - $o = ''; - $o .= $this->output->container_start('gradingsummary'); - $o .= $this->output->heading(get_string('gradingsummary', 'assign'), 3); - $o .= $this->output->box_start('boxaligncenter gradingsummarytable'); - $t = new html_table(); - $t->attributes['class'] = 'generaltable table-bordered'; - - // Visibility Status. - $cell1content = get_string('hiddenfromstudents'); - $cell2content = (!$summary->isvisible) ? get_string('yes') : get_string('no'); - $this->add_table_row_tuple($t, $cell1content, $cell2content); - - // Status. - if ($summary->teamsubmission) { - if ($summary->warnofungroupedusers === assign_grading_summary::WARN_GROUPS_REQUIRED) { - $o .= $this->output->notification(get_string('ungroupedusers', 'assign')); - } else if ($summary->warnofungroupedusers === assign_grading_summary::WARN_GROUPS_OPTIONAL) { - $o .= $this->output->notification(get_string('ungroupedusersoptional', 'assign')); - } - $cell1content = get_string('numberofteams', 'assign'); - } else { - $cell1content = get_string('numberofparticipants', 'assign'); - } - - $cell2content = $summary->participantcount; - $this->add_table_row_tuple($t, $cell1content, $cell2content); - - // Drafts count and dont show drafts count when using offline assignment. - if ($summary->submissiondraftsenabled && $summary->submissionsenabled) { - $cell1content = get_string('numberofdraftsubmissions', 'assign'); - $cell2content = $summary->submissiondraftscount; - $this->add_table_row_tuple($t, $cell1content, $cell2content); - } - - // Submitted for grading. - if ($summary->submissionsenabled) { - $cell1content = get_string('numberofsubmittedassignments', 'assign'); - $cell2content = $summary->submissionssubmittedcount; - $this->add_table_row_tuple($t, $cell1content, $cell2content); - - if (!$summary->teamsubmission) { - $cell1content = get_string('numberofsubmissionsneedgrading', 'assign'); - $cell2content = $summary->submissionsneedgradingcount; - $this->add_table_row_tuple($t, $cell1content, $cell2content); - } - } - - $time = time(); - if ($summary->duedate) { - // Time remaining. - $duedate = $summary->duedate; - $cell1content = get_string('timeremaining', 'assign'); - if ($summary->courserelativedatesmode) { - $cell2content = get_string('relativedatessubmissiontimeleft', 'mod_assign'); - } else { - if ($duedate - $time <= 0) { - $cell2content = get_string('assignmentisdue', 'assign'); - } else { - $cell2content = format_time($duedate - $time); - } - } - - $this->add_table_row_tuple($t, $cell1content, $cell2content); - - if ($duedate < $time) { - $cell1content = get_string('latesubmissions', 'assign'); - $cutoffdate = $summary->cutoffdate; - if ($cutoffdate) { - if ($cutoffdate > $time) { - $cell2content = get_string('latesubmissionsaccepted', 'assign', userdate($summary->cutoffdate)); - } else { - $cell2content = get_string('nomoresubmissionsaccepted', 'assign'); - } - - $this->add_table_row_tuple($t, $cell1content, $cell2content); - } - } - - } - - // All done - write the table. - $o .= html_writer::table($t); - $o .= $this->output->box_end(); - - // Link to the grading page. - $o .= html_writer::start_tag('center'); - $o .= $this->output->container_start('submissionlinks'); - $urlparams = array('id' => $summary->coursemoduleid, 'action' => 'grading'); - $url = new moodle_url('/mod/assign/view.php', $urlparams); - $o .= html_writer::link($url, get_string('viewgrading', 'mod_assign'), - ['class' => 'btn btn-secondary']); - if ($summary->cangrade) { - $urlparams = array('id' => $summary->coursemoduleid, 'action' => 'grader'); - $url = new moodle_url('/mod/assign/view.php', $urlparams); - $o .= html_writer::link($url, get_string('gradeverb'), - ['class' => 'btn btn-primary ml-1']); - } - $o .= $this->output->container_end(); - - // Close the container and insert a spacer. - $o .= $this->output->container_end(); - $o .= html_writer::end_tag('center'); - - return $o; - } - - /** - * Render a table containing all the current grades and feedback. - * - * @param assign_feedback_status $status - * @return string - */ - public function render_assign_feedback_status(assign_feedback_status $status) { - $o = ''; - - $o .= $this->output->container_start('feedback'); - $o .= $this->output->heading(get_string('feedback', 'assign'), 3); - $o .= $this->output->box_start('boxaligncenter feedbacktable'); - $t = new html_table(); - - // Grade. - if (isset($status->gradefordisplay)) { - $cell1content = get_string('gradenoun'); - $cell2content = $status->gradefordisplay; - $this->add_table_row_tuple($t, $cell1content, $cell2content); - - // Grade date. - $cell1content = get_string('gradedon', 'assign'); - $cell2content = userdate($status->gradeddate); - $this->add_table_row_tuple($t, $cell1content, $cell2content); - } - - if ($status->grader) { - // Grader. - $cell1content = get_string('gradedby', 'assign'); - $cell2content = $this->output->user_picture($status->grader) . - $this->output->spacer(array('width' => 30)) . - fullname($status->grader, $status->canviewfullnames); - $this->add_table_row_tuple($t, $cell1content, $cell2content); - } - - foreach ($status->feedbackplugins as $plugin) { - if ($plugin->is_enabled() && - $plugin->is_visible() && - $plugin->has_user_summary() && - !empty($status->grade) && - !$plugin->is_empty($status->grade)) { - - $displaymode = assign_feedback_plugin_feedback::SUMMARY; - $pluginfeedback = new assign_feedback_plugin_feedback($plugin, - $status->grade, - $displaymode, - $status->coursemoduleid, - $status->returnaction, - $status->returnparams); - $cell1content = $plugin->get_name(); - $cell2content = $this->render($pluginfeedback); - $this->add_table_row_tuple($t, $cell1content, $cell2content); - } - } - - $o .= html_writer::table($t); - $o .= $this->output->box_end(); - - $o .= $this->output->container_end(); - return $o; - } - - /** - * Render a compact view of the current status of the submission. - * - * @param assign_submission_status_compact $status - * @return string - */ - public function render_assign_submission_status_compact(assign_submission_status_compact $status) { - $o = ''; - $o .= $this->output->container_start('submissionstatustable'); - $o .= $this->output->heading(get_string('submission', 'assign'), 3); - $time = time(); - - if ($status->teamsubmissionenabled) { - $group = $status->submissiongroup; - if ($group) { - $team = format_string($group->name, false, $status->context); - } else if ($status->preventsubmissionnotingroup) { - if (count($status->usergroups) == 0) { - $team = '' . get_string('noteam', 'assign') . ''; - } else if (count($status->usergroups) > 1) { - $team = '' . get_string('multipleteams', 'assign') . ''; - } - } else { - $team = get_string('defaultteam', 'assign'); - } - $o .= $this->output->container(get_string('teamname', 'assign', $team), 'teamname'); - } - - if (!$status->teamsubmissionenabled) { - if ($status->submission && $status->submission->status != ASSIGN_SUBMISSION_STATUS_NEW) { - $statusstr = get_string('submissionstatus_' . $status->submission->status, 'assign'); - $o .= $this->output->container($statusstr, 'submissionstatus' . $status->submission->status); - } else { - if (!$status->submissionsenabled) { - $o .= $this->output->container(get_string('noonlinesubmissions', 'assign'), 'submissionstatus'); - } else { - $o .= $this->output->container(get_string('noattempt', 'assign'), 'submissionstatus'); - } - } - } else { - $group = $status->submissiongroup; - if (!$group && $status->preventsubmissionnotingroup) { - $o .= $this->output->container(get_string('nosubmission', 'assign'), 'submissionstatus'); - } else if ($status->teamsubmission && $status->teamsubmission->status != ASSIGN_SUBMISSION_STATUS_NEW) { - $teamstatus = $status->teamsubmission->status; - $submissionsummary = get_string('submissionstatus_' . $teamstatus, 'assign'); - $groupid = 0; - if ($status->submissiongroup) { - $groupid = $status->submissiongroup->id; - } - - $members = $status->submissiongroupmemberswhoneedtosubmit; - $userslist = array(); - foreach ($members as $member) { - $urlparams = array('id' => $member->id, 'course' => $status->courseid); - $url = new moodle_url('/user/view.php', $urlparams); - if ($status->view == assign_submission_status::GRADER_VIEW && $status->blindmarking) { - $userslist[] = $member->alias; - } else { - $fullname = fullname($member, $status->canviewfullnames); - $userslist[] = $this->output->action_link($url, $fullname); - } - } - if (count($userslist) > 0) { - $userstr = join(', ', $userslist); - $formatteduserstr = get_string('userswhoneedtosubmit', 'assign', $userstr); - $submissionsummary .= $this->output->container($formatteduserstr); - } - $o .= $this->output->container($submissionsummary, 'submissionstatus' . $status->teamsubmission->status); - } else { - if (!$status->submissionsenabled) { - $o .= $this->output->container(get_string('noonlinesubmissions', 'assign'), 'submissionstatus'); - } else { - $o .= $this->output->container(get_string('nosubmission', 'assign'), 'submissionstatus'); - } - } - } - - // Is locked? - if ($status->locked) { - $o .= $this->output->container(get_string('submissionslocked', 'assign'), 'submissionlocked'); - } - - // Grading status. - $statusstr = ''; - $classname = 'gradingstatus'; - if ($status->gradingstatus == ASSIGN_GRADING_STATUS_GRADED || - $status->gradingstatus == ASSIGN_GRADING_STATUS_NOT_GRADED) { - $statusstr = get_string($status->gradingstatus, 'assign'); - } else { - $gradingstatus = 'markingworkflowstate' . $status->gradingstatus; - $statusstr = get_string($gradingstatus, 'assign'); - } - if ($status->gradingstatus == ASSIGN_GRADING_STATUS_GRADED || - $status->gradingstatus == ASSIGN_MARKING_WORKFLOW_STATE_RELEASED) { - $classname = 'submissiongraded'; - } else { - $classname = 'submissionnotgraded'; - } - $o .= $this->output->container($statusstr, $classname); - - $submission = $status->teamsubmission ? $status->teamsubmission : $status->submission; - $duedate = $status->duedate; - if ($duedate > 0) { - - if ($status->extensionduedate) { - // Extension date. - $duedate = $status->extensionduedate; - } - - // Time remaining. - $classname = 'timeremaining'; - if ($duedate - $time <= 0) { - if (!$submission || - $submission->status != ASSIGN_SUBMISSION_STATUS_SUBMITTED) { - if ($status->submissionsenabled) { - $remaining = get_string('overdue', 'assign', format_time($time - $duedate)); - $classname = 'overdue'; - } else { - $remaining = get_string('duedatereached', 'assign'); - } - } else { - if ($submission->timemodified > $duedate) { - $remaining = get_string('submittedlate', - 'assign', - format_time($submission->timemodified - $duedate)); - $classname = 'latesubmission'; - } else { - $remaining = get_string('submittedearly', - 'assign', - format_time($submission->timemodified - $duedate)); - $classname = 'earlysubmission'; - } - } - } else { - $remaining = get_string('paramtimeremaining', 'assign', format_time($duedate - $time)); - } - $o .= $this->output->container($remaining, $classname); - } - - // Show graders whether this submission is editable by students. - if ($status->view == assign_submission_status::GRADER_VIEW) { - if ($status->canedit) { - $o .= $this->output->container(get_string('submissioneditable', 'assign'), 'submissioneditable'); - } else { - $o .= $this->output->container(get_string('submissionnoteditable', 'assign'), 'submissionnoteditable'); - } - } - - // Grading criteria preview. - if (!empty($status->gradingcontrollerpreview)) { - $o .= $this->output->container($status->gradingcontrollerpreview, 'gradingmethodpreview'); - } - - if ($submission) { - - if (!$status->teamsubmission || $status->submissiongroup != false || !$status->preventsubmissionnotingroup) { - foreach ($status->submissionplugins as $plugin) { - $pluginshowsummary = !$plugin->is_empty($submission) || !$plugin->allow_submissions(); - if ($plugin->is_enabled() && - $plugin->is_visible() && - $plugin->has_user_summary() && - $pluginshowsummary - ) { - - $displaymode = assign_submission_plugin_submission::SUMMARY; - $pluginsubmission = new assign_submission_plugin_submission($plugin, - $submission, - $displaymode, - $status->coursemoduleid, - $status->returnaction, - $status->returnparams); - $plugincomponent = $plugin->get_subtype() . '_' . $plugin->get_type(); - $o .= $this->output->container($this->render($pluginsubmission), 'assignsubmission ' . $plugincomponent); - } - } - } - } - - $o .= $this->output->container_end(); - return $o; - } - - /** - * Render a table containing the current status of the submission. - * - * @param assign_submission_status $status - * @return string - */ - public function render_assign_submission_status(assign_submission_status $status) { - $o = ''; - $o .= $this->output->container_start('submissionstatustable'); - $o .= $this->output->heading(get_string('submissionstatusheading', 'assign'), 3); - $time = time(); - - $o .= $this->output->box_start('boxaligncenter submissionsummarytable'); - - $t = new html_table(); - $t->attributes['class'] = 'generaltable table-bordered'; - - $warningmsg = ''; - if ($status->teamsubmissionenabled) { - $cell1content = get_string('submissionteam', 'assign'); - $group = $status->submissiongroup; - if ($group) { - $cell2content = format_string($group->name, false, $status->context); - } else if ($status->preventsubmissionnotingroup) { - if (count($status->usergroups) == 0) { - $notification = new \core\output\notification(get_string('noteam', 'assign'), 'error'); - $notification->set_show_closebutton(false); - $warningmsg = $this->output->notification(get_string('noteam_desc', 'assign'), 'error'); - } else if (count($status->usergroups) > 1) { - $notification = new \core\output\notification(get_string('multipleteams', 'assign'), 'error'); - $notification->set_show_closebutton(false); - $warningmsg = $this->output->notification(get_string('multipleteams_desc', 'assign'), 'error'); - } - $cell2content = $this->output->render($notification); - } else { - $cell2content = get_string('defaultteam', 'assign'); - } - - $this->add_table_row_tuple($t, $cell1content, $cell2content); - } - - if ($status->attemptreopenmethod != ASSIGN_ATTEMPT_REOPEN_METHOD_NONE) { - $currentattempt = 1; - if (!$status->teamsubmissionenabled) { - if ($status->submission) { - $currentattempt = $status->submission->attemptnumber + 1; - } - } else { - if ($status->teamsubmission) { - $currentattempt = $status->teamsubmission->attemptnumber + 1; - } - } - - $cell1content = get_string('attemptnumber', 'assign'); - $maxattempts = $status->maxattempts; - if ($maxattempts == ASSIGN_UNLIMITED_ATTEMPTS) { - $cell2content = get_string('currentattempt', 'assign', $currentattempt); - } else { - $cell2content = get_string('currentattemptof', 'assign', - array('attemptnumber' => $currentattempt, 'maxattempts' => $maxattempts)); - } - - $this->add_table_row_tuple($t, $cell1content, $cell2content); - } - - $cell1content = get_string('submissionstatus', 'assign'); - $cell2attributes = []; - if (!$status->teamsubmissionenabled) { - if ($status->submission && $status->submission->status != ASSIGN_SUBMISSION_STATUS_NEW) { - $cell2content = get_string('submissionstatus_' . $status->submission->status, 'assign'); - $cell2attributes = array('class' => 'submissionstatus' . $status->submission->status); - } else { - if (!$status->submissionsenabled) { - $cell2content = get_string('noonlinesubmissions', 'assign'); - } else { - $cell2content = get_string('noattempt', 'assign'); - } - } - } else { - $group = $status->submissiongroup; - if (!$group && $status->preventsubmissionnotingroup) { - $cell2content = get_string('nosubmission', 'assign'); - } else if ($status->teamsubmission && $status->teamsubmission->status != ASSIGN_SUBMISSION_STATUS_NEW) { - $teamstatus = $status->teamsubmission->status; - $cell2content = get_string('submissionstatus_' . $teamstatus, 'assign'); - - $members = $status->submissiongroupmemberswhoneedtosubmit; - $userslist = array(); - foreach ($members as $member) { - $urlparams = array('id' => $member->id, 'course'=>$status->courseid); - $url = new moodle_url('/user/view.php', $urlparams); - if ($status->view == assign_submission_status::GRADER_VIEW && $status->blindmarking) { - $userslist[] = $member->alias; - } else { - $fullname = fullname($member, $status->canviewfullnames); - $userslist[] = $this->output->action_link($url, $fullname); - } - } - if (count($userslist) > 0) { - $userstr = join(', ', $userslist); - $formatteduserstr = get_string('userswhoneedtosubmit', 'assign', $userstr); - $cell2content .= $this->output->container($formatteduserstr); - } - - $cell2attributes = array('class' => 'submissionstatus' . $status->teamsubmission->status); - } else { - if (!$status->submissionsenabled) { - $cell2content = get_string('noonlinesubmissions', 'assign'); - } else { - $cell2content = get_string('nosubmission', 'assign'); - } - } - } - - $this->add_table_row_tuple($t, $cell1content, $cell2content, [], $cell2attributes); - - // Is locked? - if ($status->locked) { - $cell1content = ''; - $cell2content = get_string('submissionslocked', 'assign'); - $cell2attributes = array('class' => 'submissionlocked'); - $this->add_table_row_tuple($t, $cell1content, $cell2content, [], $cell2attributes); - } - - // Grading status. - $cell1content = get_string('gradingstatus', 'assign'); - if ($status->gradingstatus == ASSIGN_GRADING_STATUS_GRADED || - $status->gradingstatus == ASSIGN_GRADING_STATUS_NOT_GRADED) { - $cell2content = get_string($status->gradingstatus, 'assign'); - } else { - $gradingstatus = 'markingworkflowstate' . $status->gradingstatus; - $cell2content = get_string($gradingstatus, 'assign'); - } - if ($status->gradingstatus == ASSIGN_GRADING_STATUS_GRADED || - $status->gradingstatus == ASSIGN_MARKING_WORKFLOW_STATE_RELEASED) { - $cell2attributes = array('class' => 'submissiongraded'); - } else { - $cell2attributes = array('class' => 'submissionnotgraded'); - } - $this->add_table_row_tuple($t, $cell1content, $cell2content, [], $cell2attributes); - - $submission = $status->teamsubmission ? $status->teamsubmission : $status->submission; - $duedate = $status->duedate; - if ($duedate > 0) { - if ($status->view == assign_submission_status::GRADER_VIEW) { - if ($status->cutoffdate) { - // Cut off date. - $cell1content = get_string('cutoffdate', 'assign'); - $cell2content = userdate($status->cutoffdate); - $this->add_table_row_tuple($t, $cell1content, $cell2content); - } - } - - if ($status->extensionduedate) { - // Extension date. - $cell1content = get_string('extensionduedate', 'assign'); - $cell2content = userdate($status->extensionduedate); - $this->add_table_row_tuple($t, $cell1content, $cell2content); - $duedate = $status->extensionduedate; - } - - // Time remaining. - $cell1content = get_string('timeremaining', 'assign'); - $cell2attributes = []; - if ($duedate - $time <= 0) { - if (!$submission || - $submission->status != ASSIGN_SUBMISSION_STATUS_SUBMITTED) { - if ($status->submissionsenabled) { - $cell2content = get_string('overdue', 'assign', format_time($time - $duedate)); - $cell2attributes = array('class' => 'overdue'); - } else { - $cell2content = get_string('duedatereached', 'assign'); - } - } else { - if ($submission->timemodified > $duedate) { - $cell2content = get_string('submittedlate', - 'assign', - format_time($submission->timemodified - $duedate)); - $cell2attributes = array('class' => 'latesubmission'); - } else { - $cell2content = get_string('submittedearly', - 'assign', - format_time($submission->timemodified - $duedate)); - $cell2attributes = array('class' => 'earlysubmission'); - } - } - } else { - $cell2content = format_time($duedate - $time); - } - $this->add_table_row_tuple($t, $cell1content, $cell2content, [], $cell2attributes); - } - - // Show graders whether this submission is editable by students. - if ($status->view == assign_submission_status::GRADER_VIEW) { - $cell1content = get_string('editingstatus', 'assign'); - if ($status->canedit) { - $cell2content = get_string('submissioneditable', 'assign'); - $cell2attributes = array('class' => 'submissioneditable'); - } else { - $cell2content = get_string('submissionnoteditable', 'assign'); - $cell2attributes = array('class' => 'submissionnoteditable'); - } - $this->add_table_row_tuple($t, $cell1content, $cell2content, [], $cell2attributes); - } - - // Grading criteria preview. - if (!empty($status->gradingcontrollerpreview)) { - $cell1content = get_string('gradingmethodpreview', 'assign'); - $cell2content = $status->gradingcontrollerpreview; - $this->add_table_row_tuple($t, $cell1content, $cell2content, [], $cell2attributes); - } - - // Last modified. - if ($submission) { - $cell1content = get_string('timemodified', 'assign'); - - if ($submission->status != ASSIGN_SUBMISSION_STATUS_NEW) { - $cell2content = userdate($submission->timemodified); - } else { - $cell2content = "-"; - } - - $this->add_table_row_tuple($t, $cell1content, $cell2content); - - if (!$status->teamsubmission || $status->submissiongroup != false || !$status->preventsubmissionnotingroup) { - foreach ($status->submissionplugins as $plugin) { - $pluginshowsummary = !$plugin->is_empty($submission) || !$plugin->allow_submissions(); - if ($plugin->is_enabled() && - $plugin->is_visible() && - $plugin->has_user_summary() && - $pluginshowsummary - ) { - - $cell1content = $plugin->get_name(); - $displaymode = assign_submission_plugin_submission::SUMMARY; - $pluginsubmission = new assign_submission_plugin_submission($plugin, - $submission, - $displaymode, - $status->coursemoduleid, - $status->returnaction, - $status->returnparams); - $cell2content = $this->render($pluginsubmission); - $this->add_table_row_tuple($t, $cell1content, $cell2content); - } - } - } - } - - $o .= $warningmsg; - $o .= html_writer::table($t); - $o .= $this->output->box_end(); - - // Links. - if ($status->view == assign_submission_status::STUDENT_VIEW) { - if ($status->canedit) { - if (!$submission || $submission->status == ASSIGN_SUBMISSION_STATUS_NEW) { - $o .= $this->output->box_start('generalbox submissionaction'); - $urlparams = array('id' => $status->coursemoduleid, 'action' => 'editsubmission'); - $o .= $this->output->single_button(new moodle_url('/mod/assign/view.php', $urlparams), - get_string('addsubmission', 'assign'), 'get'); - $o .= $this->output->box_start('boxaligncenter submithelp'); - $o .= get_string('addsubmission_help', 'assign'); - $o .= $this->output->box_end(); - $o .= $this->output->box_end(); - } else if ($submission->status == ASSIGN_SUBMISSION_STATUS_REOPENED) { - $o .= $this->output->box_start('generalbox submissionaction'); - $urlparams = array('id' => $status->coursemoduleid, - 'action' => 'editprevioussubmission', - 'sesskey'=>sesskey()); - $o .= $this->output->single_button(new moodle_url('/mod/assign/view.php', $urlparams), - get_string('addnewattemptfromprevious', 'assign'), 'get'); - $o .= $this->output->box_start('boxaligncenter submithelp'); - $o .= get_string('addnewattemptfromprevious_help', 'assign'); - $o .= $this->output->box_end(); - $o .= $this->output->box_end(); - $o .= $this->output->box_start('generalbox submissionaction'); - $urlparams = array('id' => $status->coursemoduleid, 'action' => 'editsubmission'); - $o .= $this->output->single_button(new moodle_url('/mod/assign/view.php', $urlparams), - get_string('addnewattempt', 'assign'), 'get'); - $o .= $this->output->box_start('boxaligncenter submithelp'); - $o .= get_string('addnewattempt_help', 'assign'); - $o .= $this->output->box_end(); - $o .= $this->output->box_end(); - } else { - $o .= $this->output->box_start('generalbox submissionaction'); - $urlparams = array('id' => $status->coursemoduleid, 'action' => 'editsubmission'); - $o .= $this->output->single_button(new moodle_url('/mod/assign/view.php', $urlparams), - get_string('editsubmission', 'assign'), 'get'); - $urlparams = array('id' => $status->coursemoduleid, 'action' => 'removesubmissionconfirm'); - $o .= $this->output->single_button(new moodle_url('/mod/assign/view.php', $urlparams), - get_string('removesubmission', 'assign'), 'get'); - $o .= $this->output->box_start('boxaligncenter submithelp'); - $o .= get_string('editsubmission_help', 'assign'); - $o .= $this->output->box_end(); - $o .= $this->output->box_end(); - } - } - - if ($status->cansubmit) { - $urlparams = array('id' => $status->coursemoduleid, 'action'=>'submit'); - $o .= $this->output->box_start('generalbox submissionaction'); - $o .= $this->output->single_button(new moodle_url('/mod/assign/view.php', $urlparams), - get_string('submitassignment', 'assign'), 'get'); - $o .= $this->output->box_start('boxaligncenter submithelp'); - $o .= get_string('submitassignment_help', 'assign'); - $o .= $this->output->box_end(); - $o .= $this->output->box_end(); - } - } - - $o .= $this->output->container_end(); - return $o; - } - - /** - * Output the attempt history chooser for this assignment - * - * @param assign_attempt_history_chooser $history - * @return string - */ - public function render_assign_attempt_history_chooser(assign_attempt_history_chooser $history) { - $o = ''; - - $context = $history->export_for_template($this); - $o .= $this->render_from_template('mod_assign/attempt_history_chooser', $context); - - return $o; - } - - /** - * Output the attempt history for this assignment - * - * @param assign_attempt_history $history - * @return string - */ - public function render_assign_attempt_history(assign_attempt_history $history) { - $o = ''; - - // Don't show the last one because it is the current submission. - array_pop($history->submissions); - - // Show newest to oldest. - $history->submissions = array_reverse($history->submissions); - - if (empty($history->submissions)) { - return ''; - } - - $containerid = 'attempthistory' . uniqid(); - $o .= $this->output->heading(get_string('attempthistory', 'assign'), 3); - $o .= $this->box_start('attempthistory', $containerid); - - foreach ($history->submissions as $i => $submission) { - $grade = null; - foreach ($history->grades as $onegrade) { - if ($onegrade->attemptnumber == $submission->attemptnumber) { - if ($onegrade->grade != ASSIGN_GRADE_NOT_SET) { - $grade = $onegrade; - } - break; - } - } - - if ($submission) { - $submissionsummary = userdate($submission->timemodified); - } else { - $submissionsummary = get_string('nosubmission', 'assign'); - } - - $attemptsummaryparams = array('attemptnumber'=>$submission->attemptnumber+1, - 'submissionsummary'=>$submissionsummary); - $o .= $this->heading(get_string('attemptheading', 'assign', $attemptsummaryparams), 4); - - $t = new html_table(); - - if ($submission) { - $cell1content = get_string('submissionstatus', 'assign'); - $cell2content = get_string('submissionstatus_' . $submission->status, 'assign'); - $this->add_table_row_tuple($t, $cell1content, $cell2content); - - foreach ($history->submissionplugins as $plugin) { - $pluginshowsummary = !$plugin->is_empty($submission) || !$plugin->allow_submissions(); - if ($plugin->is_enabled() && - $plugin->is_visible() && - $plugin->has_user_summary() && - $pluginshowsummary) { - - $cell1content = $plugin->get_name(); - $pluginsubmission = new assign_submission_plugin_submission($plugin, - $submission, - assign_submission_plugin_submission::SUMMARY, - $history->coursemoduleid, - $history->returnaction, - $history->returnparams); - $cell2content = $this->render($pluginsubmission); - $this->add_table_row_tuple($t, $cell1content, $cell2content); - } - } - } - - if ($grade) { - // Heading 'feedback'. - $title = get_string('feedback', 'assign', $i); - $title .= $this->output->spacer(array('width'=>10)); - if ($history->cangrade) { - // Edit previous feedback. - $returnparams = http_build_query($history->returnparams); - $urlparams = array('id' => $history->coursemoduleid, - 'rownum'=>$history->rownum, - 'useridlistid'=>$history->useridlistid, - 'attemptnumber'=>$grade->attemptnumber, - 'action'=>'grade', - 'returnaction'=>$history->returnaction, - 'returnparams'=>$returnparams); - $url = new moodle_url('/mod/assign/view.php', $urlparams); - $icon = new pix_icon('gradefeedback', - get_string('editattemptfeedback', 'assign', $grade->attemptnumber+1), - 'mod_assign'); - $title .= $this->output->action_icon($url, $icon); - } - $cell = new html_table_cell($title); - $cell->attributes['class'] = 'feedbacktitle'; - $cell->colspan = 2; - $t->data[] = new html_table_row(array($cell)); - - // Grade. - $cell1content = get_string('gradenoun'); - $cell2content = $grade->gradefordisplay; - $this->add_table_row_tuple($t, $cell1content, $cell2content); - - // Graded on. - $cell1content = get_string('gradedon', 'assign'); - $cell2content = userdate($grade->timemodified); - $this->add_table_row_tuple($t, $cell1content, $cell2content); - - // Graded by set to a real user. Not set can be empty or -1. - if (!empty($grade->grader) && is_object($grade->grader)) { - $cell1content = get_string('gradedby', 'assign'); - $cell2content = $this->output->user_picture($grade->grader) . - $this->output->spacer(array('width' => 30)) . fullname($grade->grader); - $this->add_table_row_tuple($t, $cell1content, $cell2content); - } - - // Feedback from plugins. - foreach ($history->feedbackplugins as $plugin) { - if ($plugin->is_enabled() && - $plugin->is_visible() && - $plugin->has_user_summary() && - !$plugin->is_empty($grade)) { - - $pluginfeedback = new assign_feedback_plugin_feedback( - $plugin, $grade, assign_feedback_plugin_feedback::SUMMARY, $history->coursemoduleid, - $history->returnaction, $history->returnparams - ); - - $cell1content = $plugin->get_name(); - $cell2content = $this->render($pluginfeedback); - $this->add_table_row_tuple($t, $cell1content, $cell2content); - } - - } - - } - - $o .= html_writer::table($t); - } - $o .= $this->box_end(); - - $this->page->requires->yui_module('moodle-mod_assign-history', 'Y.one("#' . $containerid . '").history'); - - return $o; - } - - /** - * Render a submission plugin submission - * - * @param assign_submission_plugin_submission $submissionplugin - * @return string - */ - public function render_assign_submission_plugin_submission(assign_submission_plugin_submission $submissionplugin) { - $o = ''; - - if ($submissionplugin->view == assign_submission_plugin_submission::SUMMARY) { - $showviewlink = false; - $summary = $submissionplugin->plugin->view_summary($submissionplugin->submission, - $showviewlink); - - $classsuffix = $submissionplugin->plugin->get_subtype() . - '_' . - $submissionplugin->plugin->get_type() . - '_' . - $submissionplugin->submission->id; - - $o .= $this->output->box_start('boxaligncenter plugincontentsummary summary_' . $classsuffix); - - $link = ''; - if ($showviewlink) { - $previewstr = get_string('viewsubmission', 'assign'); - $icon = $this->output->pix_icon('t/preview', $previewstr); - - $expandstr = get_string('viewfull', 'assign'); - $expandicon = $this->output->pix_icon('t/switch_plus', $expandstr); - $options = array( - 'class' => 'expandsummaryicon expand_' . $classsuffix, - 'aria-label' => $expandstr, - 'role' => 'button', - 'aria-expanded' => 'false' - ); - $o .= html_writer::link('', $expandicon, $options); - - $jsparams = array($submissionplugin->plugin->get_subtype(), - $submissionplugin->plugin->get_type(), - $submissionplugin->submission->id); - - $this->page->requires->js_init_call('M.mod_assign.init_plugin_summary', $jsparams); - - $action = 'viewplugin' . $submissionplugin->plugin->get_subtype(); - $returnparams = http_build_query($submissionplugin->returnparams); - $link .= ''; - - $link .= $this->output->spacer(array('width'=>15)); - } - - $o .= $link . $summary; - $o .= $this->output->box_end(); - if ($showviewlink) { - $o .= $this->output->box_start('boxaligncenter hidefull full_' . $classsuffix); - $collapsestr = get_string('viewsummary', 'assign'); - $options = array( - 'class' => 'expandsummaryicon contract_' . $classsuffix, - 'aria-label' => $collapsestr, - 'role' => 'button', - 'aria-expanded' => 'true' - ); - $collapseicon = $this->output->pix_icon('t/switch_minus', $collapsestr); - $o .= html_writer::link('', $collapseicon, $options); - - $o .= $submissionplugin->plugin->view($submissionplugin->submission); - $o .= $this->output->box_end(); - } - } else if ($submissionplugin->view == assign_submission_plugin_submission::FULL) { - $o .= $this->output->box_start('boxaligncenter submissionfull'); - $o .= $submissionplugin->plugin->view($submissionplugin->submission); - $o .= $this->output->box_end(); - } - - return $o; - } - - /** - * Render the grading table. - * - * @param assign_grading_table $table - * @return string - */ - public function render_assign_grading_table(assign_grading_table $table) { - $o = ''; - $o .= $this->output->box_start('boxaligncenter gradingtable'); - - $this->page->requires->js_init_call('M.mod_assign.init_grading_table', array()); - $this->page->requires->string_for_js('nousersselected', 'assign'); - $this->page->requires->string_for_js('batchoperationconfirmgrantextension', 'assign'); - $this->page->requires->string_for_js('batchoperationconfirmlock', 'assign'); - $this->page->requires->string_for_js('batchoperationconfirmremovesubmission', 'assign'); - $this->page->requires->string_for_js('batchoperationconfirmreverttodraft', 'assign'); - $this->page->requires->string_for_js('batchoperationconfirmunlock', 'assign'); - $this->page->requires->string_for_js('batchoperationconfirmaddattempt', 'assign'); - $this->page->requires->string_for_js('batchoperationconfirmdownloadselected', 'assign'); - $this->page->requires->string_for_js('batchoperationconfirmsetmarkingworkflowstate', 'assign'); - $this->page->requires->string_for_js('batchoperationconfirmsetmarkingallocation', 'assign'); - $this->page->requires->string_for_js('editaction', 'assign'); - foreach ($table->plugingradingbatchoperations as $plugin => $operations) { - foreach ($operations as $operation => $description) { - $this->page->requires->string_for_js('batchoperationconfirm' . $operation, - 'assignfeedback_' . $plugin); - } - } - $o .= $this->flexible_table($table, $table->get_rows_per_page(), true); - $o .= $this->output->box_end(); - - return $o; - } - - /** - * Render a feedback plugin feedback - * - * @param assign_feedback_plugin_feedback $feedbackplugin - * @return string - */ - public function render_assign_feedback_plugin_feedback(assign_feedback_plugin_feedback $feedbackplugin) { - $o = ''; - - if ($feedbackplugin->view == assign_feedback_plugin_feedback::SUMMARY) { - $showviewlink = false; - $summary = $feedbackplugin->plugin->view_summary($feedbackplugin->grade, $showviewlink); - - $classsuffix = $feedbackplugin->plugin->get_subtype() . - '_' . - $feedbackplugin->plugin->get_type() . - '_' . - $feedbackplugin->grade->id; - $o .= $this->output->box_start('boxaligncenter plugincontentsummary summary_' . $classsuffix); - - $link = ''; - if ($showviewlink) { - $previewstr = get_string('viewfeedback', 'assign'); - $icon = $this->output->pix_icon('t/preview', $previewstr); - - $expandstr = get_string('viewfull', 'assign'); - $expandicon = $this->output->pix_icon('t/switch_plus', $expandstr); - $options = array( - 'class' => 'expandsummaryicon expand_' . $classsuffix, - 'aria-label' => $expandstr, - 'role' => 'button', - 'aria-expanded' => 'false' - ); - $o .= html_writer::link('', $expandicon, $options); - - $jsparams = array($feedbackplugin->plugin->get_subtype(), - $feedbackplugin->plugin->get_type(), - $feedbackplugin->grade->id); - $this->page->requires->js_init_call('M.mod_assign.init_plugin_summary', $jsparams); - - $urlparams = array('id' => $feedbackplugin->coursemoduleid, - 'gid'=>$feedbackplugin->grade->id, - 'plugin'=>$feedbackplugin->plugin->get_type(), - 'action'=>'viewplugin' . $feedbackplugin->plugin->get_subtype(), - 'returnaction'=>$feedbackplugin->returnaction, - 'returnparams'=>http_build_query($feedbackplugin->returnparams)); - $url = new moodle_url('/mod/assign/view.php', $urlparams); - $link .= ''; - - $link .= $this->output->spacer(array('width'=>15)); - } - - $o .= $link . $summary; - $o .= $this->output->box_end(); - if ($showviewlink) { - $o .= $this->output->box_start('boxaligncenter hidefull full_' . $classsuffix); - $collapsestr = get_string('viewsummary', 'assign'); - $options = array( - 'class' => 'expandsummaryicon contract_' . $classsuffix, - 'aria-label' => $collapsestr, - 'role' => 'button', - 'aria-expanded' => 'true' - ); - $collapseicon = $this->output->pix_icon('t/switch_minus', $collapsestr); - $o .= html_writer::link('', $collapseicon, $options); - - $o .= $feedbackplugin->plugin->view($feedbackplugin->grade); - $o .= $this->output->box_end(); - } - } else if ($feedbackplugin->view == assign_feedback_plugin_feedback::FULL) { - $o .= $this->output->box_start('boxaligncenter feedbackfull'); - $o .= $feedbackplugin->plugin->view($feedbackplugin->grade); - $o .= $this->output->box_end(); - } - - return $o; - } - - /** - * Render a course index summary - * - * @param assign_course_index_summary $indexsummary - * @return string - */ - public function render_assign_course_index_summary(assign_course_index_summary $indexsummary) { - $o = ''; - - $strplural = get_string('modulenameplural', 'assign'); - $strsectionname = $indexsummary->courseformatname; - $strduedate = get_string('duedate', 'assign'); - $strsubmission = get_string('submission', 'assign'); - $strgrade = get_string('gradenoun'); - - $table = new html_table(); - if ($indexsummary->usesections) { - $table->head = array ($strsectionname, $strplural, $strduedate, $strsubmission, $strgrade); - $table->align = array ('left', 'left', 'center', 'right', 'right'); - } else { - $table->head = array ($strplural, $strduedate, $strsubmission, $strgrade); - $table->align = array ('left', 'left', 'center', 'right'); - } - $table->data = array(); - - $currentsection = ''; - foreach ($indexsummary->assignments as $info) { - $params = array('id' => $info['cmid']); - $link = html_writer::link(new moodle_url('/mod/assign/view.php', $params), - $info['cmname']); - $due = $info['timedue'] ? userdate($info['timedue']) : '-'; - - $printsection = ''; - if ($indexsummary->usesections) { - if ($info['sectionname'] !== $currentsection) { - if ($info['sectionname']) { - $printsection = $info['sectionname']; - } - if ($currentsection !== '') { - $table->data[] = 'hr'; - } - $currentsection = $info['sectionname']; - } - } - - if ($indexsummary->usesections) { - $row = array($printsection, $link, $due, $info['submissioninfo'], $info['gradeinfo']); - } else { - $row = array($link, $due, $info['submissioninfo'], $info['gradeinfo']); - } - $table->data[] = $row; - } - - $o .= html_writer::table($table); - - return $o; - } - - - - /** - * Internal function - creates htmls structure suitable for YUI tree. - * - * @param assign_files $tree - * @param array $dir - * @return string - */ - protected function htmllize_tree(assign_files $tree, $dir) { - global $CFG; - $yuiconfig = array(); - $yuiconfig['type'] = 'html'; - - if (empty($dir['subdirs']) and empty($dir['files'])) { - return ''; - } - - $result = '
    '; - foreach ($dir['subdirs'] as $subdir) { - $image = $this->output->pix_icon(file_folder_icon(), - $subdir['dirname'], - 'moodle', - array('class'=>'icon')); - $result .= '
  • ' . - '
    ' . $image . ' ' . s($subdir['dirname']) . '
    ' . - $this->htmllize_tree($tree, $subdir) . - '
  • '; - } - - foreach ($dir['files'] as $file) { - $filename = $file->get_filename(); - if ($CFG->enableplagiarism) { - require_once($CFG->libdir.'/plagiarismlib.php'); - $plagiarismlinks = plagiarism_get_links(array('userid'=>$file->get_userid(), - 'file'=>$file, - 'cmid'=>$tree->cm->id, - 'course'=>$tree->course)); - } else { - $plagiarismlinks = ''; - } - $image = $this->output->pix_icon(file_file_icon($file), - $filename, - 'moodle', - array('class'=>'icon')); - $result .= '
  • ' . - '
    ' . - '
    ' . $image . ' ' . - $file->fileurl . ' ' . - $plagiarismlinks . ' ' . - $file->portfoliobutton . ' ' . - '
    ' . - '
    ' . $file->timemodified . '
    ' . - '
    ' . - '
  • '; - } - - $result .= '
'; - - return $result; - } - - /** - * Helper method dealing with the fact we can not just fetch the output of flexible_table - * - * @param flexible_table $table The table to render - * @param int $rowsperpage How many assignments to render in a page - * @param bool $displaylinks - Whether to render links in the table - * (e.g. downloads would not enable this) - * @return string HTML - */ - protected function flexible_table(flexible_table $table, $rowsperpage, $displaylinks) { - - $o = ''; - ob_start(); - $table->out($rowsperpage, $displaylinks); - $o = ob_get_contents(); - ob_end_clean(); - - return $o; - } - - /** - * Helper method dealing with the fact we can not just fetch the output of moodleforms - * - * @param moodleform $mform - * @return string HTML - */ - protected function moodleform(moodleform $mform) { - - $o = ''; - ob_start(); - $mform->display(); - $o = ob_get_contents(); - ob_end_clean(); - - return $o; - } - - /** - * Defer to template.. - * - * @param grading_app $app - All the data to render the grading app. - */ - public function render_grading_app(grading_app $app) { - $context = $app->export_for_template($this); - return $this->render_from_template('mod_assign/grading_app', $context); - } -} - +// TODO - MDL-72749 add debugging message. diff --git a/mod/assign/tests/locallib_test.php b/mod/assign/tests/locallib_test.php index 5d098f90b2b..00fbb337e87 100644 --- a/mod/assign/tests/locallib_test.php +++ b/mod/assign/tests/locallib_test.php @@ -4308,7 +4308,7 @@ Anchor link 2:Link text $_GET['group'] = $activegroup->id; /** @var assign $assign */ - $header = new assign_header( + $header = new \mod_assign\output\assign_header( $assign->get_instance(), $assign->get_context(), false, diff --git a/mod/assign/upgrade.txt b/mod/assign/upgrade.txt index 130cf298119..4a703e6a509 100644 --- a/mod/assign/upgrade.txt +++ b/mod/assign/upgrade.txt @@ -1,6 +1,9 @@ This files describes API changes in the assign code. === 4.0 === * The method \assign::grading_disabled() now has optional $gradinginfo parameter to improve performance +* Renderer (renderer.php) has been moved from mod root to classes/output/ to be more PSR compliant. +* Class assign_header has been moved from renderable.php to classes/ouput/assign_header.php +* Class assign_submion_status has been moved from renderable.php to classes/ouput/assign_submion_status.php === 3.9 === diff --git a/mod/assign/version.php b/mod/assign/version.php index 08be89e031e..f047cc5a8eb 100644 --- a/mod/assign/version.php +++ b/mod/assign/version.php @@ -25,5 +25,5 @@ defined('MOODLE_INTERNAL') || die(); $plugin->component = 'mod_assign'; // Full name of the plugin (used for diagnostics). -$plugin->version = 2021052503; // The current module version (Date: YYYYMMDDXX). +$plugin->version = 2021093000; // The current module version (Date: YYYYMMDDXX). $plugin->requires = 2021052500; // Requires this Moodle version.