mirror of
https://github.com/moodle/moodle.git
synced 2025-01-19 06:18:28 +01:00
77d746a2f5
In order to use the overall feedback in assessments of example submissions and in the assessment form preview, significant improvements in the rendering machinery were done. Workshop class provides two new methods overall_feedback_content_options() and overall_feedback_attachment_options() as they are needed at various scripts and libraries. Overall feedback is displayed as a part of the workshop_assessment_form only if the form is in editable mode (not frozen). If the form is displayed in read-only (frozen) mode, the caller is expected to render the overall feedback and list of attachments (the editor and filemanager elements do not support frozen mode). To do so, the renderable workshop_assessment now loads overall feedback data and provides two new methods get_overall_feedback_content() and get_overall_feedback_attachments() to be used by the renderer. Renderable workshop_submission, workshop_assessment and related classes now accept the workshop instance as the first parameter in their constructors. This way, these renderable classes have access to the workshop API. In the future, the rendering of submission files should be improved in the same way as is done in this patch (i.e. moving the logic and data preparation out of the renderer into the renderable classes).
1129 lines
44 KiB
PHP
1129 lines
44 KiB
PHP
<?php
|
|
|
|
// This file is part of Moodle - http://moodle.org/
|
|
//
|
|
// Moodle is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// Moodle is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
/**
|
|
* Workshop module renderering methods are defined here
|
|
*
|
|
* @package mod
|
|
* @subpackage workshop
|
|
* @copyright 2009 David Mudrak <david.mudrak@gmail.com>
|
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|
*/
|
|
|
|
defined('MOODLE_INTERNAL') || die();
|
|
|
|
/**
|
|
* Workshop module renderer class
|
|
*
|
|
* @copyright 2009 David Mudrak <david.mudrak@gmail.com>
|
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|
*/
|
|
class mod_workshop_renderer extends plugin_renderer_base {
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// External API - methods to render workshop renderable components
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* Renders workshop message
|
|
*
|
|
* @param workshop_message $message to display
|
|
* @return string html code
|
|
*/
|
|
protected function render_workshop_message(workshop_message $message) {
|
|
|
|
$text = $message->get_message();
|
|
$url = $message->get_action_url();
|
|
$label = $message->get_action_label();
|
|
|
|
if (empty($text) and empty($label)) {
|
|
return '';
|
|
}
|
|
|
|
switch ($message->get_type()) {
|
|
case workshop_message::TYPE_OK:
|
|
$sty = 'ok';
|
|
break;
|
|
case workshop_message::TYPE_ERROR:
|
|
$sty = 'error';
|
|
break;
|
|
default:
|
|
$sty = 'info';
|
|
}
|
|
|
|
$o = html_writer::tag('span', $message->get_message());
|
|
|
|
if (!is_null($url) and !is_null($label)) {
|
|
$o .= $this->output->single_button($url, $label, 'get');
|
|
}
|
|
|
|
return $this->output->container($o, array('message', $sty));
|
|
}
|
|
|
|
|
|
/**
|
|
* Renders full workshop submission
|
|
*
|
|
* @param workshop_submission $submission
|
|
* @return string HTML
|
|
*/
|
|
protected function render_workshop_submission(workshop_submission $submission) {
|
|
global $CFG;
|
|
|
|
$o = ''; // output HTML code
|
|
$anonymous = $submission->is_anonymous();
|
|
$classes = 'submission-full';
|
|
if ($anonymous) {
|
|
$classes .= ' anonymous';
|
|
}
|
|
$o .= $this->output->container_start($classes);
|
|
$o .= $this->output->container_start('header');
|
|
|
|
$title = format_string($submission->title);
|
|
|
|
if ($this->page->url != $submission->url) {
|
|
$title = html_writer::link($submission->url, $title);
|
|
}
|
|
|
|
$o .= $this->output->heading($title, 3, 'title');
|
|
|
|
if (!$anonymous) {
|
|
$author = new stdclass();
|
|
$author->id = $submission->authorid;
|
|
$author->firstname = $submission->authorfirstname;
|
|
$author->lastname = $submission->authorlastname;
|
|
$author->picture = $submission->authorpicture;
|
|
$author->imagealt = $submission->authorimagealt;
|
|
$author->email = $submission->authoremail;
|
|
$userpic = $this->output->user_picture($author, array('courseid' => $this->page->course->id, 'size' => 64));
|
|
$userurl = new moodle_url('/user/view.php',
|
|
array('id' => $author->id, 'course' => $this->page->course->id));
|
|
$a = new stdclass();
|
|
$a->name = fullname($author);
|
|
$a->url = $userurl->out();
|
|
$byfullname = get_string('byfullname', 'workshop', $a);
|
|
$oo = $this->output->container($userpic, 'picture');
|
|
$oo .= $this->output->container($byfullname, 'fullname');
|
|
|
|
$o .= $this->output->container($oo, 'author');
|
|
}
|
|
|
|
$created = get_string('userdatecreated', 'workshop', userdate($submission->timecreated));
|
|
$o .= $this->output->container($created, 'userdate created');
|
|
|
|
if ($submission->timemodified > $submission->timecreated) {
|
|
$modified = get_string('userdatemodified', 'workshop', userdate($submission->timemodified));
|
|
$o .= $this->output->container($modified, 'userdate modified');
|
|
}
|
|
|
|
$o .= $this->output->container_end(); // end of header
|
|
|
|
$content = format_text($submission->content, $submission->contentformat, array('overflowdiv'=>true));
|
|
$content = file_rewrite_pluginfile_urls($content, 'pluginfile.php', $this->page->context->id,
|
|
'mod_workshop', 'submission_content', $submission->id);
|
|
if (!empty($content)) {
|
|
if (!empty($CFG->enableplagiarism)) {
|
|
require_once($CFG->libdir.'/plagiarismlib.php');
|
|
$content .= plagiarism_get_links(array('userid' => $submission->authorid,
|
|
'content' => $submission->content,
|
|
'cmid' => $this->page->cm->id,
|
|
'course' => $this->page->course));
|
|
}
|
|
}
|
|
$o .= $this->output->container($content, 'content');
|
|
|
|
$o .= $this->helper_submission_attachments($submission->id, 'html');
|
|
|
|
$o .= $this->output->container_end(); // end of submission-full
|
|
|
|
return $o;
|
|
}
|
|
|
|
/**
|
|
* Renders short summary of the submission
|
|
*
|
|
* @param workshop_submission_summary $summary
|
|
* @return string text to be echo'ed
|
|
*/
|
|
protected function render_workshop_submission_summary(workshop_submission_summary $summary) {
|
|
|
|
$o = ''; // output HTML code
|
|
$anonymous = $summary->is_anonymous();
|
|
$classes = 'submission-summary';
|
|
|
|
if ($anonymous) {
|
|
$classes .= ' anonymous';
|
|
}
|
|
|
|
$gradestatus = '';
|
|
|
|
if ($summary->status == 'notgraded') {
|
|
$classes .= ' notgraded';
|
|
$gradestatus = $this->output->container(get_string('nogradeyet', 'workshop'), 'grade-status');
|
|
|
|
} else if ($summary->status == 'graded') {
|
|
$classes .= ' graded';
|
|
$gradestatus = $this->output->container(get_string('alreadygraded', 'workshop'), 'grade-status');
|
|
}
|
|
|
|
$o .= $this->output->container_start($classes); // main wrapper
|
|
$o .= html_writer::link($summary->url, format_string($summary->title), array('class' => 'title'));
|
|
|
|
if (!$anonymous) {
|
|
$author = new stdClass();
|
|
$author->id = $summary->authorid;
|
|
$author->firstname = $summary->authorfirstname;
|
|
$author->lastname = $summary->authorlastname;
|
|
$author->picture = $summary->authorpicture;
|
|
$author->imagealt = $summary->authorimagealt;
|
|
$author->email = $summary->authoremail;
|
|
$userpic = $this->output->user_picture($author, array('courseid' => $this->page->course->id, 'size' => 35));
|
|
$userurl = new moodle_url('/user/view.php',
|
|
array('id' => $author->id, 'course' => $this->page->course->id));
|
|
$a = new stdClass();
|
|
$a->name = fullname($author);
|
|
$a->url = $userurl->out();
|
|
$byfullname = get_string('byfullname', 'workshop', $a);
|
|
|
|
$oo = $this->output->container($userpic, 'picture');
|
|
$oo .= $this->output->container($byfullname, 'fullname');
|
|
$o .= $this->output->container($oo, 'author');
|
|
}
|
|
|
|
$created = get_string('userdatecreated', 'workshop', userdate($summary->timecreated));
|
|
$o .= $this->output->container($created, 'userdate created');
|
|
|
|
if ($summary->timemodified > $summary->timecreated) {
|
|
$modified = get_string('userdatemodified', 'workshop', userdate($summary->timemodified));
|
|
$o .= $this->output->container($modified, 'userdate modified');
|
|
}
|
|
|
|
$o .= $gradestatus;
|
|
$o .= $this->output->container_end(); // end of the main wrapper
|
|
return $o;
|
|
}
|
|
|
|
/**
|
|
* Renders full workshop example submission
|
|
*
|
|
* @param workshop_example_submission $example
|
|
* @return string HTML
|
|
*/
|
|
protected function render_workshop_example_submission(workshop_example_submission $example) {
|
|
|
|
$o = ''; // output HTML code
|
|
$classes = 'submission-full example';
|
|
$o .= $this->output->container_start($classes);
|
|
$o .= $this->output->container_start('header');
|
|
$o .= $this->output->heading(format_string($example->title), 3, 'title');
|
|
$o .= $this->output->container_end(); // end of header
|
|
|
|
$content = format_text($example->content, $example->contentformat, array('overflowdiv'=>true));
|
|
$content = file_rewrite_pluginfile_urls($content, 'pluginfile.php', $this->page->context->id,
|
|
'mod_workshop', 'submission_content', $example->id);
|
|
$o .= $this->output->container($content, 'content');
|
|
|
|
$o .= $this->helper_submission_attachments($example->id, 'html');
|
|
|
|
$o .= $this->output->container_end(); // end of submission-full
|
|
|
|
return $o;
|
|
}
|
|
|
|
/**
|
|
* Renders short summary of the example submission
|
|
*
|
|
* @param workshop_example_submission_summary $summary
|
|
* @return string text to be echo'ed
|
|
*/
|
|
protected function render_workshop_example_submission_summary(workshop_example_submission_summary $summary) {
|
|
|
|
$o = ''; // output HTML code
|
|
|
|
// wrapping box
|
|
$o .= $this->output->box_start('generalbox example-summary ' . $summary->status);
|
|
|
|
// title
|
|
$o .= $this->output->container_start('example-title');
|
|
$o .= html_writer::link($summary->url, format_string($summary->title), array('class' => 'title'));
|
|
|
|
if ($summary->editable) {
|
|
$o .= $this->output->action_icon($summary->editurl, new pix_icon('i/edit', get_string('edit')));
|
|
}
|
|
$o .= $this->output->container_end();
|
|
|
|
// additional info
|
|
if ($summary->status == 'notgraded') {
|
|
$o .= $this->output->container(get_string('nogradeyet', 'workshop'), 'example-info nograde');
|
|
} else {
|
|
$o .= $this->output->container(get_string('gradeinfo', 'workshop' , $summary->gradeinfo), 'example-info grade');
|
|
}
|
|
|
|
// button to assess
|
|
$button = new single_button($summary->assessurl, $summary->assesslabel, 'get');
|
|
$o .= $this->output->container($this->output->render($button), 'example-actions');
|
|
|
|
// end of wrapping box
|
|
$o .= $this->output->box_end();
|
|
|
|
return $o;
|
|
}
|
|
|
|
/**
|
|
* Renders the user plannner tool
|
|
*
|
|
* @param workshop_user_plan $plan prepared for the user
|
|
* @return string html code to be displayed
|
|
*/
|
|
protected function render_workshop_user_plan(workshop_user_plan $plan) {
|
|
$table = new html_table();
|
|
$table->attributes['class'] = 'userplan';
|
|
$table->head = array();
|
|
$table->colclasses = array();
|
|
$row = new html_table_row();
|
|
$row->attributes['class'] = 'phasetasks';
|
|
foreach ($plan->phases as $phasecode => $phase) {
|
|
$title = html_writer::tag('span', $phase->title);
|
|
$actions = '';
|
|
foreach ($phase->actions as $action) {
|
|
switch ($action->type) {
|
|
case 'switchphase':
|
|
$icon = 'i/marker';
|
|
if ($phasecode == workshop::PHASE_ASSESSMENT
|
|
and $plan->workshop->phase == workshop::PHASE_SUBMISSION
|
|
and $plan->workshop->phaseswitchassessment) {
|
|
$icon = 'i/scheduled';
|
|
}
|
|
$actions .= $this->output->action_icon($action->url, new pix_icon($icon, get_string('switchphase', 'workshop')));
|
|
break;
|
|
}
|
|
}
|
|
if (!empty($actions)) {
|
|
$actions = $this->output->container($actions, 'actions');
|
|
}
|
|
$table->head[] = $this->output->container($title . $actions);
|
|
$classes = 'phase' . $phasecode;
|
|
if ($phase->active) {
|
|
$classes .= ' active';
|
|
} else {
|
|
$classes .= ' nonactive';
|
|
}
|
|
$table->colclasses[] = $classes;
|
|
$cell = new html_table_cell();
|
|
$cell->text = $this->helper_user_plan_tasks($phase->tasks);
|
|
$row->cells[] = $cell;
|
|
}
|
|
$table->data = array($row);
|
|
|
|
return html_writer::table($table);
|
|
}
|
|
|
|
/**
|
|
* Renders the result of the submissions allocation process
|
|
*
|
|
* @param workshop_allocation_result $result as returned by the allocator's init() method
|
|
* @return string HTML to be echoed
|
|
*/
|
|
protected function render_workshop_allocation_result(workshop_allocation_result $result) {
|
|
|
|
$status = $result->get_status();
|
|
|
|
if (is_null($status) or $status == workshop_allocation_result::STATUS_VOID) {
|
|
debugging('Attempt to render workshop_allocation_result with empty status', DEBUG_DEVELOPER);
|
|
return '';
|
|
}
|
|
|
|
switch ($status) {
|
|
case workshop_allocation_result::STATUS_FAILED:
|
|
if ($message = $result->get_message()) {
|
|
$message = new workshop_message($message, workshop_message::TYPE_ERROR);
|
|
} else {
|
|
$message = new workshop_message(get_string('allocationerror', 'workshop'), workshop_message::TYPE_ERROR);
|
|
}
|
|
break;
|
|
|
|
case workshop_allocation_result::STATUS_CONFIGURED:
|
|
if ($message = $result->get_message()) {
|
|
$message = new workshop_message($message, workshop_message::TYPE_INFO);
|
|
} else {
|
|
$message = new workshop_message(get_string('allocationconfigured', 'workshop'), workshop_message::TYPE_INFO);
|
|
}
|
|
break;
|
|
|
|
case workshop_allocation_result::STATUS_EXECUTED:
|
|
if ($message = $result->get_message()) {
|
|
$message = new workshop_message($message, workshop_message::TYPE_OK);
|
|
} else {
|
|
$message = new workshop_message(get_string('allocationdone', 'workshop'), workshop_message::TYPE_OK);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
throw new coding_exception('Unknown allocation result status', $status);
|
|
}
|
|
|
|
// start with the message
|
|
$o = $this->render($message);
|
|
|
|
// display the details about the process if available
|
|
$logs = $result->get_logs();
|
|
if (is_array($logs) and !empty($logs)) {
|
|
$o .= html_writer::start_tag('ul', array('class' => 'allocation-init-results'));
|
|
foreach ($logs as $log) {
|
|
if ($log->type == 'debug' and !debugging('', DEBUG_DEVELOPER)) {
|
|
// display allocation debugging messages for developers only
|
|
continue;
|
|
}
|
|
$class = $log->type;
|
|
if ($log->indent) {
|
|
$class .= ' indent';
|
|
}
|
|
$o .= html_writer::tag('li', $log->message, array('class' => $class)).PHP_EOL;
|
|
}
|
|
$o .= html_writer::end_tag('ul');
|
|
}
|
|
|
|
return $o;
|
|
}
|
|
|
|
/**
|
|
* Renders the workshop grading report
|
|
*
|
|
* @param workshop_grading_report $gradingreport
|
|
* @return string html code
|
|
*/
|
|
protected function render_workshop_grading_report(workshop_grading_report $gradingreport) {
|
|
|
|
$data = $gradingreport->get_data();
|
|
$options = $gradingreport->get_options();
|
|
$grades = $data->grades;
|
|
$userinfo = $data->userinfo;
|
|
|
|
if (empty($grades)) {
|
|
return '';
|
|
}
|
|
|
|
$table = new html_table();
|
|
$table->attributes['class'] = 'grading-report';
|
|
|
|
$sortbyfirstname = $this->helper_sortable_heading(get_string('firstname'), 'firstname', $options->sortby, $options->sorthow);
|
|
$sortbylastname = $this->helper_sortable_heading(get_string('lastname'), 'lastname', $options->sortby, $options->sorthow);
|
|
if (self::fullname_format() == 'lf') {
|
|
$sortbyname = $sortbylastname . ' / ' . $sortbyfirstname;
|
|
} else {
|
|
$sortbyname = $sortbyfirstname . ' / ' . $sortbylastname;
|
|
}
|
|
|
|
$table->head = array();
|
|
$table->head[] = $sortbyname;
|
|
$table->head[] = $this->helper_sortable_heading(get_string('submission', 'workshop'), 'submissiontitle',
|
|
$options->sortby, $options->sorthow);
|
|
$table->head[] = $this->helper_sortable_heading(get_string('receivedgrades', 'workshop'));
|
|
if ($options->showsubmissiongrade) {
|
|
$table->head[] = $this->helper_sortable_heading(get_string('submissiongradeof', 'workshop', $data->maxgrade),
|
|
'submissiongrade', $options->sortby, $options->sorthow);
|
|
}
|
|
$table->head[] = $this->helper_sortable_heading(get_string('givengrades', 'workshop'));
|
|
if ($options->showgradinggrade) {
|
|
$table->head[] = $this->helper_sortable_heading(get_string('gradinggradeof', 'workshop', $data->maxgradinggrade),
|
|
'gradinggrade', $options->sortby, $options->sorthow);
|
|
}
|
|
|
|
$table->rowclasses = array();
|
|
$table->colclasses = array();
|
|
$table->data = array();
|
|
|
|
foreach ($grades as $participant) {
|
|
$numofreceived = count($participant->reviewedby);
|
|
$numofgiven = count($participant->reviewerof);
|
|
$published = $participant->submissionpublished;
|
|
|
|
// compute the number of <tr> table rows needed to display this participant
|
|
if ($numofreceived > 0 and $numofgiven > 0) {
|
|
$numoftrs = workshop::lcm($numofreceived, $numofgiven);
|
|
$spanreceived = $numoftrs / $numofreceived;
|
|
$spangiven = $numoftrs / $numofgiven;
|
|
} elseif ($numofreceived == 0 and $numofgiven > 0) {
|
|
$numoftrs = $numofgiven;
|
|
$spanreceived = $numoftrs;
|
|
$spangiven = $numoftrs / $numofgiven;
|
|
} elseif ($numofreceived > 0 and $numofgiven == 0) {
|
|
$numoftrs = $numofreceived;
|
|
$spanreceived = $numoftrs / $numofreceived;
|
|
$spangiven = $numoftrs;
|
|
} else {
|
|
$numoftrs = 1;
|
|
$spanreceived = 1;
|
|
$spangiven = 1;
|
|
}
|
|
|
|
for ($tr = 0; $tr < $numoftrs; $tr++) {
|
|
$row = new html_table_row();
|
|
if ($published) {
|
|
$row->attributes['class'] = 'published';
|
|
}
|
|
// column #1 - participant - spans over all rows
|
|
if ($tr == 0) {
|
|
$cell = new html_table_cell();
|
|
$cell->text = $this->helper_grading_report_participant($participant, $userinfo);
|
|
$cell->rowspan = $numoftrs;
|
|
$cell->attributes['class'] = 'participant';
|
|
$row->cells[] = $cell;
|
|
}
|
|
// column #2 - submission - spans over all rows
|
|
if ($tr == 0) {
|
|
$cell = new html_table_cell();
|
|
$cell->text = $this->helper_grading_report_submission($participant);
|
|
$cell->rowspan = $numoftrs;
|
|
$cell->attributes['class'] = 'submission';
|
|
$row->cells[] = $cell;
|
|
}
|
|
// column #3 - received grades
|
|
if ($tr % $spanreceived == 0) {
|
|
$idx = intval($tr / $spanreceived);
|
|
$assessment = self::array_nth($participant->reviewedby, $idx);
|
|
$cell = new html_table_cell();
|
|
$cell->text = $this->helper_grading_report_assessment($assessment, $options->showreviewernames, $userinfo,
|
|
get_string('gradereceivedfrom', 'workshop'));
|
|
$cell->rowspan = $spanreceived;
|
|
$cell->attributes['class'] = 'receivedgrade';
|
|
if (is_null($assessment) or is_null($assessment->grade)) {
|
|
$cell->attributes['class'] .= ' null';
|
|
} else {
|
|
$cell->attributes['class'] .= ' notnull';
|
|
}
|
|
$row->cells[] = $cell;
|
|
}
|
|
// column #4 - total grade for submission
|
|
if ($options->showsubmissiongrade and $tr == 0) {
|
|
$cell = new html_table_cell();
|
|
$cell->text = $this->helper_grading_report_grade($participant->submissiongrade, $participant->submissiongradeover);
|
|
$cell->rowspan = $numoftrs;
|
|
$cell->attributes['class'] = 'submissiongrade';
|
|
$row->cells[] = $cell;
|
|
}
|
|
// column #5 - given grades
|
|
if ($tr % $spangiven == 0) {
|
|
$idx = intval($tr / $spangiven);
|
|
$assessment = self::array_nth($participant->reviewerof, $idx);
|
|
$cell = new html_table_cell();
|
|
$cell->text = $this->helper_grading_report_assessment($assessment, $options->showauthornames, $userinfo,
|
|
get_string('gradegivento', 'workshop'));
|
|
$cell->rowspan = $spangiven;
|
|
$cell->attributes['class'] = 'givengrade';
|
|
if (is_null($assessment) or is_null($assessment->grade)) {
|
|
$cell->attributes['class'] .= ' null';
|
|
} else {
|
|
$cell->attributes['class'] .= ' notnull';
|
|
}
|
|
$row->cells[] = $cell;
|
|
}
|
|
// column #6 - total grade for assessment
|
|
if ($options->showgradinggrade and $tr == 0) {
|
|
$cell = new html_table_cell();
|
|
$cell->text = $this->helper_grading_report_grade($participant->gradinggrade);
|
|
$cell->rowspan = $numoftrs;
|
|
$cell->attributes['class'] = 'gradinggrade';
|
|
$row->cells[] = $cell;
|
|
}
|
|
|
|
$table->data[] = $row;
|
|
}
|
|
}
|
|
|
|
return html_writer::table($table);
|
|
}
|
|
|
|
/**
|
|
* Renders the feedback for the author of the submission
|
|
*
|
|
* @param workshop_feedback_author $feedback
|
|
* @return string HTML
|
|
*/
|
|
protected function render_workshop_feedback_author(workshop_feedback_author $feedback) {
|
|
return $this->helper_render_feedback($feedback);
|
|
}
|
|
|
|
/**
|
|
* Renders the feedback for the reviewer of the submission
|
|
*
|
|
* @param workshop_feedback_reviewer $feedback
|
|
* @return string HTML
|
|
*/
|
|
protected function render_workshop_feedback_reviewer(workshop_feedback_reviewer $feedback) {
|
|
return $this->helper_render_feedback($feedback);
|
|
}
|
|
|
|
/**
|
|
* Helper method to rendering feedback
|
|
*
|
|
* @param workshop_feedback_author|workshop_feedback_reviewer $feedback
|
|
* @return string HTML
|
|
*/
|
|
private function helper_render_feedback($feedback) {
|
|
|
|
$o = ''; // output HTML code
|
|
$o .= $this->output->container_start('feedback feedbackforauthor');
|
|
$o .= $this->output->container_start('header');
|
|
$o .= $this->output->heading(get_string('feedbackby', 'workshop', s(fullname($feedback->get_provider()))), 3, 'title');
|
|
|
|
$userpic = $this->output->user_picture($feedback->get_provider(), array('courseid' => $this->page->course->id, 'size' => 32));
|
|
$o .= $this->output->container($userpic, 'picture');
|
|
$o .= $this->output->container_end(); // end of header
|
|
|
|
$content = format_text($feedback->get_content(), $feedback->get_format(), array('overflowdiv' => true));
|
|
$o .= $this->output->container($content, 'content');
|
|
|
|
$o .= $this->output->container_end();
|
|
|
|
return $o;
|
|
}
|
|
|
|
/**
|
|
* Renders the full assessment
|
|
*
|
|
* @param workshop_assessment $assessment
|
|
* @return string HTML
|
|
*/
|
|
protected function render_workshop_assessment(workshop_assessment $assessment) {
|
|
|
|
$o = ''; // output HTML code
|
|
$anonymous = is_null($assessment->reviewer);
|
|
$classes = 'assessment-full';
|
|
if ($anonymous) {
|
|
$classes .= ' anonymous';
|
|
}
|
|
|
|
$o .= $this->output->container_start($classes);
|
|
$o .= $this->output->container_start('header');
|
|
|
|
if (!empty($assessment->title)) {
|
|
$title = s($assessment->title);
|
|
} else {
|
|
$title = get_string('assessment', 'workshop');
|
|
}
|
|
if (($assessment->url instanceof moodle_url) and ($this->page->url != $assessment->url)) {
|
|
$o .= $this->output->container(html_writer::link($assessment->url, $title), 'title');
|
|
} else {
|
|
$o .= $this->output->container($title, 'title');
|
|
}
|
|
|
|
if (!$anonymous) {
|
|
$reviewer = $assessment->reviewer;
|
|
$userpic = $this->output->user_picture($reviewer, array('courseid' => $this->page->course->id, 'size' => 32));
|
|
|
|
$userurl = new moodle_url('/user/view.php',
|
|
array('id' => $reviewer->id, 'course' => $this->page->course->id));
|
|
$a = new stdClass();
|
|
$a->name = fullname($reviewer);
|
|
$a->url = $userurl->out();
|
|
$byfullname = get_string('assessmentby', 'workshop', $a);
|
|
$oo = $this->output->container($userpic, 'picture');
|
|
$oo .= $this->output->container($byfullname, 'fullname');
|
|
|
|
$o .= $this->output->container($oo, 'reviewer');
|
|
}
|
|
|
|
if (is_null($assessment->realgrade)) {
|
|
$o .= $this->output->container(
|
|
get_string('notassessed', 'workshop'),
|
|
'grade nograde'
|
|
);
|
|
} else {
|
|
$a = new stdClass();
|
|
$a->max = $assessment->maxgrade;
|
|
$a->received = $assessment->realgrade;
|
|
$o .= $this->output->container(
|
|
get_string('gradeinfo', 'workshop', $a),
|
|
'grade'
|
|
);
|
|
|
|
if (!is_null($assessment->weight) and $assessment->weight != 1) {
|
|
$o .= $this->output->container(
|
|
get_string('weightinfo', 'workshop', $assessment->weight),
|
|
'weight'
|
|
);
|
|
}
|
|
}
|
|
|
|
$o .= $this->output->container_start('actions');
|
|
foreach ($assessment->actions as $action) {
|
|
$o .= $this->output->single_button($action->url, $action->label, $action->method);
|
|
}
|
|
$o .= $this->output->container_end(); // actions
|
|
|
|
$o .= $this->output->container_end(); // header
|
|
|
|
if (!is_null($assessment->form)) {
|
|
$o .= print_collapsible_region_start('assessment-form-wrapper', uniqid('workshop-assessment'),
|
|
get_string('assessmentform', 'workshop'), '', false, true);
|
|
$o .= $this->output->container(self::moodleform($assessment->form), 'assessment-form');
|
|
$o .= print_collapsible_region_end(true);
|
|
|
|
if (!$assessment->form->is_editable()) {
|
|
$o .= $this->overall_feedback($assessment);
|
|
}
|
|
}
|
|
|
|
$o .= $this->output->container_end(); // main wrapper
|
|
|
|
return $o;
|
|
}
|
|
|
|
/**
|
|
* Renders the assessment of an example submission
|
|
*
|
|
* @param workshop_example_assessment $assessment
|
|
* @return string HTML
|
|
*/
|
|
protected function render_workshop_example_assessment(workshop_example_assessment $assessment) {
|
|
return $this->render_workshop_assessment($assessment);
|
|
}
|
|
|
|
/**
|
|
* Renders the reference assessment of an example submission
|
|
*
|
|
* @param workshop_example_reference_assessment $assessment
|
|
* @return string HTML
|
|
*/
|
|
protected function render_workshop_example_reference_assessment(workshop_example_reference_assessment $assessment) {
|
|
return $this->render_workshop_assessment($assessment);
|
|
}
|
|
|
|
/**
|
|
* Renders the overall feedback for the author of the submission
|
|
*
|
|
* @param workshop_assessment $assessment
|
|
* @return string HTML
|
|
*/
|
|
protected function overall_feedback(workshop_assessment $assessment) {
|
|
|
|
$content = $assessment->get_overall_feedback_content();
|
|
|
|
if ($content === false) {
|
|
return '';
|
|
}
|
|
|
|
$o = '';
|
|
|
|
if (!is_null($content)) {
|
|
$o .= $this->output->container($content, 'content');
|
|
}
|
|
|
|
$attachments = $assessment->get_overall_feedback_attachments();
|
|
|
|
if (!empty($attachments)) {
|
|
$o .= $this->output->container_start('attachments');
|
|
$images = '';
|
|
$files = '';
|
|
foreach ($attachments as $attachment) {
|
|
$icon = $this->output->pix_icon(file_file_icon($attachment), get_mimetype_description($attachment),
|
|
'moodle', array('class' => 'icon'));
|
|
$link = html_writer::link($attachment->fileurl, $icon.' '.substr($attachment->filepath.$attachment->filename, 1));
|
|
if (file_mimetype_in_typegroup($attachment->mimetype, 'web_image')) {
|
|
$preview = html_writer::empty_tag('img', array('src' => $attachment->previewurl, 'alt' => '', 'class' => 'preview'));
|
|
$preview = html_writer::tag('a', $preview, array('href' => $attachment->fileurl));
|
|
$images .= $this->output->container($preview);
|
|
} else {
|
|
$files .= html_writer::tag('li', $link, array('class' => $attachment->mimetype));
|
|
}
|
|
}
|
|
if ($images) {
|
|
$images = $this->output->container($images, 'images');
|
|
}
|
|
|
|
if ($files) {
|
|
$files = html_writer::tag('ul', $files, array('class' => 'files'));
|
|
}
|
|
|
|
$o .= $images.$files;
|
|
$o .= $this->output->container_end();
|
|
}
|
|
|
|
if ($o === '') {
|
|
return '';
|
|
}
|
|
|
|
$o = $this->output->box($o, 'overallfeedback');
|
|
$o = print_collapsible_region($o, 'overall-feedback-wrapper', uniqid('workshop-overall-feedback'),
|
|
get_string('overallfeedback', 'workshop'), '', false, true);
|
|
|
|
return $o;
|
|
}
|
|
|
|
/**
|
|
* Renders a perpage selector for workshop listings
|
|
*
|
|
* The scripts using this have to define the $PAGE->url prior to calling this
|
|
* and deal with eventually submitted value themselves.
|
|
*
|
|
* @param int $current current value of the perpage parameter
|
|
* @return string HTML
|
|
*/
|
|
public function perpage_selector($current=10) {
|
|
|
|
$options = array();
|
|
foreach (array(10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 200, 300, 400, 500, 1000) as $option) {
|
|
if ($option != $current) {
|
|
$options[$option] = $option;
|
|
}
|
|
}
|
|
$select = new single_select($this->page->url, 'perpage', $options, '', array('' => get_string('showingperpagechange', 'mod_workshop')));
|
|
$select->label = get_string('showingperpage', 'mod_workshop', $current);
|
|
$select->method = 'post';
|
|
|
|
return $this->output->container($this->output->render($select), 'perpagewidget');
|
|
}
|
|
|
|
/**
|
|
* Renders the user's final grades
|
|
*
|
|
* @param workshop_final_grades $grades with the info about grades in the gradebook
|
|
* @return string HTML
|
|
*/
|
|
protected function render_workshop_final_grades(workshop_final_grades $grades) {
|
|
|
|
$out = html_writer::start_tag('div', array('class' => 'finalgrades'));
|
|
|
|
if (!empty($grades->submissiongrade)) {
|
|
$cssclass = 'grade submissiongrade';
|
|
if ($grades->submissiongrade->hidden) {
|
|
$cssclass .= ' hiddengrade';
|
|
}
|
|
$out .= html_writer::tag(
|
|
'div',
|
|
html_writer::tag('div', get_string('submissiongrade', 'mod_workshop'), array('class' => 'gradetype')) .
|
|
html_writer::tag('div', $grades->submissiongrade->str_long_grade, array('class' => 'gradevalue')),
|
|
array('class' => $cssclass)
|
|
);
|
|
}
|
|
|
|
if (!empty($grades->assessmentgrade)) {
|
|
$cssclass = 'grade assessmentgrade';
|
|
if ($grades->assessmentgrade->hidden) {
|
|
$cssclass .= ' hiddengrade';
|
|
}
|
|
$out .= html_writer::tag(
|
|
'div',
|
|
html_writer::tag('div', get_string('gradinggrade', 'mod_workshop'), array('class' => 'gradetype')) .
|
|
html_writer::tag('div', $grades->assessmentgrade->str_long_grade, array('class' => 'gradevalue')),
|
|
array('class' => $cssclass)
|
|
);
|
|
}
|
|
|
|
$out .= html_writer::end_tag('div');
|
|
|
|
return $out;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// Internal rendering helper methods
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* Renders a list of files attached to the submission
|
|
*
|
|
* If format==html, then format a html string. If format==text, then format a text-only string.
|
|
* Otherwise, returns html for non-images and html to display the image inline.
|
|
*
|
|
* @param int $submissionid submission identifier
|
|
* @param string format the format of the returned string - html|text
|
|
* @return string formatted text to be echoed
|
|
*/
|
|
protected function helper_submission_attachments($submissionid, $format = 'html') {
|
|
global $CFG;
|
|
require_once($CFG->libdir.'/filelib.php');
|
|
|
|
$fs = get_file_storage();
|
|
$ctx = $this->page->context;
|
|
$files = $fs->get_area_files($ctx->id, 'mod_workshop', 'submission_attachment', $submissionid);
|
|
|
|
$outputimgs = ''; // images to be displayed inline
|
|
$outputfiles = ''; // list of attachment files
|
|
|
|
foreach ($files as $file) {
|
|
if ($file->is_directory()) {
|
|
continue;
|
|
}
|
|
|
|
$filepath = $file->get_filepath();
|
|
$filename = $file->get_filename();
|
|
$fileurl = moodle_url::make_pluginfile_url($ctx->id, 'mod_workshop', 'submission_attachment',
|
|
$submissionid, $filepath, $filename, true);
|
|
$embedurl = moodle_url::make_pluginfile_url($ctx->id, 'mod_workshop', 'submission_attachment',
|
|
$submissionid, $filepath, $filename, false);
|
|
$embedurl = new moodle_url($embedurl, array('preview' => 'bigthumb'));
|
|
$type = $file->get_mimetype();
|
|
$image = $this->output->pix_icon(file_file_icon($file), get_mimetype_description($file), 'moodle', array('class' => 'icon'));
|
|
|
|
$linkhtml = html_writer::link($fileurl, $image) . substr($filepath, 1) . html_writer::link($fileurl, $filename);
|
|
$linktxt = "$filename [$fileurl]";
|
|
|
|
if ($format == 'html') {
|
|
if (file_mimetype_in_typegroup($type, 'web_image')) {
|
|
$preview = html_writer::empty_tag('img', array('src' => $embedurl, 'alt' => '', 'class' => 'preview'));
|
|
$preview = html_writer::tag('a', $preview, array('href' => $fileurl));
|
|
$outputimgs .= $this->output->container($preview);
|
|
|
|
} else {
|
|
$outputfiles .= html_writer::tag('li', $linkhtml, array('class' => $type));
|
|
}
|
|
|
|
} else if ($format == 'text') {
|
|
$outputfiles .= $linktxt . PHP_EOL;
|
|
}
|
|
|
|
if (!empty($CFG->enableplagiarism)) {
|
|
require_once($CFG->libdir.'/plagiarismlib.php');
|
|
$outputfiles .= plagiarism_get_links(array('userid' => $file->get_userid(),
|
|
'file' => $file,
|
|
'cmid' => $this->page->cm->id,
|
|
'course' => $this->page->course->id));
|
|
}
|
|
}
|
|
|
|
if ($format == 'html') {
|
|
if ($outputimgs) {
|
|
$outputimgs = $this->output->container($outputimgs, 'images');
|
|
}
|
|
|
|
if ($outputfiles) {
|
|
$outputfiles = html_writer::tag('ul', $outputfiles, array('class' => 'files'));
|
|
}
|
|
|
|
return $this->output->container($outputimgs . $outputfiles, 'attachments');
|
|
|
|
} else {
|
|
return $outputfiles;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Renders the tasks for the single phase in the user plan
|
|
*
|
|
* @param stdClass $tasks
|
|
* @return string html code
|
|
*/
|
|
protected function helper_user_plan_tasks(array $tasks) {
|
|
$out = '';
|
|
foreach ($tasks as $taskcode => $task) {
|
|
$classes = '';
|
|
$icon = null;
|
|
if ($task->completed === true) {
|
|
$classes .= ' completed';
|
|
} elseif ($task->completed === false) {
|
|
$classes .= ' fail';
|
|
} elseif ($task->completed === 'info') {
|
|
$classes .= ' info';
|
|
}
|
|
if (is_null($task->link)) {
|
|
$title = $task->title;
|
|
} else {
|
|
$title = html_writer::link($task->link, $task->title);
|
|
}
|
|
$title = $this->output->container($title, 'title');
|
|
$details = $this->output->container($task->details, 'details');
|
|
$out .= html_writer::tag('li', $title . $details, array('class' => $classes));
|
|
}
|
|
if ($out) {
|
|
$out = html_writer::tag('ul', $out, array('class' => 'tasks'));
|
|
}
|
|
return $out;
|
|
}
|
|
|
|
/**
|
|
* Renders a text with icons to sort by the given column
|
|
*
|
|
* This is intended for table headings.
|
|
*
|
|
* @param string $text The heading text
|
|
* @param string $sortid The column id used for sorting
|
|
* @param string $sortby Currently sorted by (column id)
|
|
* @param string $sorthow Currently sorted how (ASC|DESC)
|
|
*
|
|
* @return string
|
|
*/
|
|
protected function helper_sortable_heading($text, $sortid=null, $sortby=null, $sorthow=null) {
|
|
global $PAGE;
|
|
|
|
$out = html_writer::tag('span', $text, array('class'=>'text'));
|
|
|
|
if (!is_null($sortid)) {
|
|
if ($sortby !== $sortid or $sorthow !== 'ASC') {
|
|
$url = new moodle_url($PAGE->url);
|
|
$url->params(array('sortby' => $sortid, 'sorthow' => 'ASC'));
|
|
$out .= $this->output->action_icon($url, new pix_icon('t/sort_asc', get_string('sortasc', 'workshop')),
|
|
null, array('class' => 'iconsort sort asc'));
|
|
}
|
|
if ($sortby !== $sortid or $sorthow !== 'DESC') {
|
|
$url = new moodle_url($PAGE->url);
|
|
$url->params(array('sortby' => $sortid, 'sorthow' => 'DESC'));
|
|
$out .= $this->output->action_icon($url, new pix_icon('t/sort_desc', get_string('sortdesc', 'workshop')),
|
|
null, array('class' => 'iconsort sort desc'));
|
|
}
|
|
}
|
|
return $out;
|
|
}
|
|
|
|
/**
|
|
* @param stdClass $participant
|
|
* @param array $userinfo
|
|
* @return string
|
|
*/
|
|
protected function helper_grading_report_participant(stdclass $participant, array $userinfo) {
|
|
$userid = $participant->userid;
|
|
$out = $this->output->user_picture($userinfo[$userid], array('courseid' => $this->page->course->id, 'size' => 35));
|
|
$out .= html_writer::tag('span', fullname($userinfo[$userid]));
|
|
|
|
return $out;
|
|
}
|
|
|
|
/**
|
|
* @param stdClass $participant
|
|
* @return string
|
|
*/
|
|
protected function helper_grading_report_submission(stdclass $participant) {
|
|
global $CFG;
|
|
|
|
if (is_null($participant->submissionid)) {
|
|
$out = $this->output->container(get_string('nosubmissionfound', 'workshop'), 'info');
|
|
} else {
|
|
$url = new moodle_url('/mod/workshop/submission.php',
|
|
array('cmid' => $this->page->context->instanceid, 'id' => $participant->submissionid));
|
|
$out = html_writer::link($url, format_string($participant->submissiontitle), array('class'=>'title'));
|
|
}
|
|
|
|
return $out;
|
|
}
|
|
|
|
/**
|
|
* @todo Highlight the nulls
|
|
* @param stdClass|null $assessment
|
|
* @param bool $shownames
|
|
* @param string $separator between the grade and the reviewer/author
|
|
* @return string
|
|
*/
|
|
protected function helper_grading_report_assessment($assessment, $shownames, array $userinfo, $separator) {
|
|
global $CFG;
|
|
|
|
if (is_null($assessment)) {
|
|
return get_string('nullgrade', 'workshop');
|
|
}
|
|
$a = new stdclass();
|
|
$a->grade = is_null($assessment->grade) ? get_string('nullgrade', 'workshop') : $assessment->grade;
|
|
$a->gradinggrade = is_null($assessment->gradinggrade) ? get_string('nullgrade', 'workshop') : $assessment->gradinggrade;
|
|
$a->weight = $assessment->weight;
|
|
// grrr the following logic should really be handled by a future language pack feature
|
|
if (is_null($assessment->gradinggradeover)) {
|
|
if ($a->weight == 1) {
|
|
$grade = get_string('formatpeergrade', 'workshop', $a);
|
|
} else {
|
|
$grade = get_string('formatpeergradeweighted', 'workshop', $a);
|
|
}
|
|
} else {
|
|
$a->gradinggradeover = $assessment->gradinggradeover;
|
|
if ($a->weight == 1) {
|
|
$grade = get_string('formatpeergradeover', 'workshop', $a);
|
|
} else {
|
|
$grade = get_string('formatpeergradeoverweighted', 'workshop', $a);
|
|
}
|
|
}
|
|
$url = new moodle_url('/mod/workshop/assessment.php',
|
|
array('asid' => $assessment->assessmentid));
|
|
$grade = html_writer::link($url, $grade, array('class'=>'grade'));
|
|
|
|
if ($shownames) {
|
|
$userid = $assessment->userid;
|
|
$name = $this->output->user_picture($userinfo[$userid], array('courseid' => $this->page->course->id, 'size' => 16));
|
|
$name .= html_writer::tag('span', fullname($userinfo[$userid]), array('class' => 'fullname'));
|
|
$name = $separator . html_writer::tag('span', $name, array('class' => 'user'));
|
|
} else {
|
|
$name = '';
|
|
}
|
|
|
|
return $this->output->container($grade . $name, 'assessmentdetails');
|
|
}
|
|
|
|
/**
|
|
* Formats the aggreagated grades
|
|
*/
|
|
protected function helper_grading_report_grade($grade, $over=null) {
|
|
$a = new stdclass();
|
|
$a->grade = is_null($grade) ? get_string('nullgrade', 'workshop') : $grade;
|
|
if (is_null($over)) {
|
|
$text = get_string('formataggregatedgrade', 'workshop', $a);
|
|
} else {
|
|
$a->over = is_null($over) ? get_string('nullgrade', 'workshop') : $over;
|
|
$text = get_string('formataggregatedgradeover', 'workshop', $a);
|
|
}
|
|
return $text;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// Static helpers
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* Helper method dealing with the fact we can not just fetch the output of moodleforms
|
|
*
|
|
* @param moodleform $mform
|
|
* @return string HTML
|
|
*/
|
|
protected static function moodleform(moodleform $mform) {
|
|
|
|
ob_start();
|
|
$mform->display();
|
|
$o = ob_get_contents();
|
|
ob_end_clean();
|
|
|
|
return $o;
|
|
}
|
|
|
|
/**
|
|
* Helper function returning the n-th item of the array
|
|
*
|
|
* @param array $a
|
|
* @param int $n from 0 to m, where m is th number of items in the array
|
|
* @return mixed the $n-th element of $a
|
|
*/
|
|
protected static function array_nth(array $a, $n) {
|
|
$keys = array_keys($a);
|
|
if ($n < 0 or $n > count($keys) - 1) {
|
|
return null;
|
|
}
|
|
$key = $keys[$n];
|
|
return $a[$key];
|
|
}
|
|
|
|
/**
|
|
* Tries to guess the fullname format set at the site
|
|
*
|
|
* @return string fl|lf
|
|
*/
|
|
protected static function fullname_format() {
|
|
$fake = new stdclass(); // fake user
|
|
$fake->lastname = 'LLLL';
|
|
$fake->firstname = 'FFFF';
|
|
$fullname = get_string('fullnamedisplay', '', $fake);
|
|
if (strpos($fullname, 'LLLL') < strpos($fullname, 'FFFF')) {
|
|
return 'lf';
|
|
} else {
|
|
return 'fl';
|
|
}
|
|
}
|
|
}
|