Proyectos de Subversion Moodle

Rev

Rev 1 | | Comparar con el anterior | Ultima modificación | Ver Log |

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