MDL-30998: updated docblocks for advanced grading
[moodle.git] / grade / grading / form / rubric / renderer.php
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/>.
17 /**
18  * Contains renderer used for displaying rubric
19  *
20  * @package    gradingform_rubric
21  * @copyright  2011 Marina Glancy
22  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
25 defined('MOODLE_INTERNAL') || die();
27 /**
28  * Grading method plugin renderer
29  *
30  * @copyright  2011 Marina Glancy
31  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
32  */
33 class gradingform_rubric_renderer extends plugin_renderer_base {
35     /**
36      * This function returns html code for displaying criterion. Depending on $mode it may be the
37      * code to edit rubric, to preview the rubric, to evaluate somebody or to review the evaluation.
38      *
39      * This function may be called from display_rubric() to display the whole rubric, or it can be
40      * called by itself to return a template used by JavaScript to add new empty criteria to the
41      * rubric being designed.
42      * In this case it will use macros like {NAME}, {LEVELS}, {CRITERION-id}, etc.
43      *
44      * When overriding this function it is very important to remember that all elements of html
45      * form (in edit or evaluate mode) must have the name $elementname.
46      *
47      * Also JavaScript relies on the class names of elements and when developer changes them
48      * script might stop working.
49      *
50      * @param int $mode rubric display mode, see {@link gradingform_rubric_controller}
51      * @param array $options display options for this rubric, defaults are: {@link gradingform_rubric_controller::get_default_options()}
52      * @param string $elementname the name of the form element (in editor mode) or the prefix for div ids (in view mode)
53      * @param array|null $criterion criterion data
54      * @param string $levelsstr evaluated templates for this criterion levels
55      * @param array|null $value (only in view mode) teacher's feedback on this criterion
56      * @return string
57      */
58     public function criterion_template($mode, $options, $elementname = '{NAME}', $criterion = null, $levelsstr = '{LEVELS}', $value = null) {
59         // TODO MDL-31235 description format, remark format
60         if ($criterion === null || !is_array($criterion) || !array_key_exists('id', $criterion)) {
61             $criterion = array('id' => '{CRITERION-id}', 'description' => '{CRITERION-description}', 'sortorder' => '{CRITERION-sortorder}', 'class' => '{CRITERION-class}');
62         } else {
63             foreach (array('sortorder', 'description', 'class') as $key) {
64                 // set missing array elements to empty strings to avoid warnings
65                 if (!array_key_exists($key, $criterion)) {
66                     $criterion[$key] = '';
67                 }
68             }
69         }
70         $criteriontemplate = html_writer::start_tag('tr', array('class' => 'criterion'. $criterion['class'], 'id' => '{NAME}-criteria-{CRITERION-id}'));
71         if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FULL) {
72             $criteriontemplate .= html_writer::start_tag('td', array('class' => 'controls'));
73             foreach (array('moveup', 'delete', 'movedown') as $key) {
74                 $value = get_string('criterion'.$key, 'gradingform_rubric');
75                 $button = html_writer::empty_tag('input', array('type' => 'submit', 'name' => '{NAME}[criteria][{CRITERION-id}]['.$key.']',
76                     'id' => '{NAME}-criteria-{CRITERION-id}-'.$key, 'value' => $value, 'title' => $value, 'tabindex' => -1));
77                 $criteriontemplate .= html_writer::tag('div', $button, array('class' => $key));
78             }
79             $criteriontemplate .= html_writer::end_tag('td'); // .controls
80             $criteriontemplate .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => '{NAME}[criteria][{CRITERION-id}][sortorder]', 'value' => $criterion['sortorder']));
81             $description = html_writer::tag('textarea', htmlspecialchars($criterion['description']), array('name' => '{NAME}[criteria][{CRITERION-id}][description]', 'cols' => '10', 'rows' => '5'));
82         } else {
83             if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FROZEN) {
84                 $criteriontemplate .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => '{NAME}[criteria][{CRITERION-id}][sortorder]', 'value' => $criterion['sortorder']));
85                 $criteriontemplate .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => '{NAME}[criteria][{CRITERION-id}][description]', 'value' => $criterion['description']));
86             }
87             $description = $criterion['description'];
88         }
89         $descriptionclass = 'description';
90         if (isset($criterion['error_description'])) {
91             $descriptionclass .= ' error';
92         }
93         $criteriontemplate .= html_writer::tag('td', $description, array('class' => $descriptionclass, 'id' => '{NAME}-criteria-{CRITERION-id}-description'));
94         $levelsstrtable = html_writer::tag('table', html_writer::tag('tr', $levelsstr, array('id' => '{NAME}-criteria-{CRITERION-id}-levels')));
95         $levelsclass = 'levels';
96         if (isset($criterion['error_levels'])) {
97             $levelsclass .= ' error';
98         }
99         $criteriontemplate .= html_writer::tag('td', $levelsstrtable, array('class' => $levelsclass));
100         if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FULL) {
101             $value = get_string('criterionaddlevel', 'gradingform_rubric');
102             $button = html_writer::empty_tag('input', array('type' => 'submit', 'name' => '{NAME}[criteria][{CRITERION-id}][levels][addlevel]',
103                 'id' => '{NAME}-criteria-{CRITERION-id}-levels-addlevel', 'value' => $value, 'title' => $value));
104             $criteriontemplate .= html_writer::tag('td', $button, array('class' => 'addlevel'));
105         }
106         $displayremark = ($options['enableremarks'] && ($mode != gradingform_rubric_controller::DISPLAY_VIEW || $options['showremarksstudent']));
107         if ($displayremark) {
108             $currentremark = '';
109             if (isset($value['remark'])) {
110                 $currentremark = $value['remark'];
111             }
112             if ($mode == gradingform_rubric_controller::DISPLAY_EVAL) {
113                 $input = html_writer::tag('textarea', htmlspecialchars($currentremark), array('name' => '{NAME}[criteria][{CRITERION-id}][remark]', 'cols' => '10', 'rows' => '5'));
114                 $criteriontemplate .= html_writer::tag('td', $input, array('class' => 'remark'));
115             } else if ($mode == gradingform_rubric_controller::DISPLAY_EVAL_FROZEN) {
116                 $criteriontemplate .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => '{NAME}[criteria][{CRITERION-id}][remark]', 'value' => $currentremark));
117             }else if ($mode == gradingform_rubric_controller::DISPLAY_REVIEW || $mode == gradingform_rubric_controller::DISPLAY_VIEW) {
118                 $criteriontemplate .= html_writer::tag('td', $currentremark, array('class' => 'remark'));
119             }
120         }
121         $criteriontemplate .= html_writer::end_tag('tr'); // .criterion
123         $criteriontemplate = str_replace('{NAME}', $elementname, $criteriontemplate);
124         $criteriontemplate = str_replace('{CRITERION-id}', $criterion['id'], $criteriontemplate);
125         return $criteriontemplate;
126     }
128     /**
129      * This function returns html code for displaying one level of one criterion. Depending on $mode
130      * it may be the code to edit rubric, to preview the rubric, to evaluate somebody or to review the evaluation.
131      *
132      * This function may be called from display_rubric() to display the whole rubric, or it can be
133      * called by itself to return a template used by JavaScript to add new empty level to the
134      * criterion during the design of rubric.
135      * In this case it will use macros like {NAME}, {CRITERION-id}, {LEVEL-id}, etc.
136      *
137      * When overriding this function it is very important to remember that all elements of html
138      * form (in edit or evaluate mode) must have the name $elementname.
139      *
140      * Also JavaScript relies on the class names of elements and when developer changes them
141      * script might stop working.
142      *
143      * @param int $mode rubric display mode see {@link gradingform_rubric_controller}
144      * @param array $options display options for this rubric, defaults are: {@link gradingform_rubric_controller::get_default_options()}
145      * @param string $elementname the name of the form element (in editor mode) or the prefix for div ids (in view mode)
146      * @param string|int $criterionid either id of the nesting criterion or a macro for template
147      * @param array|null $level level data, also in view mode it might also have property $level['checked'] whether this level is checked
148      * @return string
149      */
150     public function level_template($mode, $options, $elementname = '{NAME}', $criterionid = '{CRITERION-id}', $level = null) {
151         // TODO MDL-31235 definition format
152         if (!isset($level['id'])) {
153             $level = array('id' => '{LEVEL-id}', 'definition' => '{LEVEL-definition}', 'score' => '{LEVEL-score}', 'class' => '{LEVEL-class}', 'checked' => false);
154         } else {
155             foreach (array('score', 'definition', 'class', 'checked') as $key) {
156                 // set missing array elements to empty strings to avoid warnings
157                 if (!array_key_exists($key, $level)) {
158                     $level[$key] = '';
159                 }
160             }
161         }
163         // Template for one level within one criterion
164         $tdattributes = array('id' => '{NAME}-criteria-{CRITERION-id}-levels-{LEVEL-id}', 'class' => 'level'. $level['class']);
165         if (isset($level['tdwidth'])) {
166             $tdattributes['width'] = round($level['tdwidth']).'%';
167         }
168         $leveltemplate = html_writer::start_tag('td', $tdattributes);
169         $leveltemplate .= html_writer::start_tag('div', array('class' => 'level-wrapper'));
170         if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FULL) {
171             $definition = html_writer::tag('textarea', htmlspecialchars($level['definition']), array('name' => '{NAME}[criteria][{CRITERION-id}][levels][{LEVEL-id}][definition]', 'cols' => '10', 'rows' => '4'));
172             $score = html_writer::label(get_string('criterionempty', 'gradingform_rubric'), '{NAME}criteria{CRITERION-id}levels{LEVEL-id}', false, array('class' => 'accesshide'));
173             $score .= html_writer::empty_tag('input', array('type' => 'text','id' => '{NAME}criteria{CRITERION-id}levels{LEVEL-id}', 'name' => '{NAME}[criteria][{CRITERION-id}][levels][{LEVEL-id}][score]', 'size' => '3', 'value' => $level['score']));
174         } else {
175             if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FROZEN) {
176                 $leveltemplate .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => '{NAME}[criteria][{CRITERION-id}][levels][{LEVEL-id}][definition]', 'value' => $level['definition']));
177                 $leveltemplate .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => '{NAME}[criteria][{CRITERION-id}][levels][{LEVEL-id}][score]', 'value' => $level['score']));
178             }
179             $definition = $level['definition'];
180             $score = $level['score'];
181         }
182         if ($mode == gradingform_rubric_controller::DISPLAY_EVAL) {
183             $input = html_writer::empty_tag('input', array('type' => 'radio', 'name' => '{NAME}[criteria][{CRITERION-id}][levelid]', 'value' => $level['id']) +
184                     ($level['checked'] ? array('checked' => 'checked') : array()));
185             $leveltemplate .= html_writer::tag('div', $input, array('class' => 'radio'));
186         }
187         if ($mode == gradingform_rubric_controller::DISPLAY_EVAL_FROZEN && $level['checked']) {
188             $leveltemplate .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => '{NAME}[criteria][{CRITERION-id}][levelid]', 'value' => $level['id']));
189         }
190         $score = html_writer::tag('span', $score, array('id' => '{NAME}-criteria-{CRITERION-id}-levels-{LEVEL-id}-score', 'class' => 'scorevalue'));
191         $definitionclass = 'definition';
192         if (isset($level['error_definition'])) {
193             $definitionclass .= ' error';
194         }
195         $leveltemplate .= html_writer::tag('div', $definition, array('class' => $definitionclass, 'id' => '{NAME}-criteria-{CRITERION-id}-levels-{LEVEL-id}-definition'));
196         $displayscore = true;
197         if (!$options['showscoreteacher'] && in_array($mode, array(gradingform_rubric_controller::DISPLAY_EVAL, gradingform_rubric_controller::DISPLAY_EVAL_FROZEN, gradingform_rubric_controller::DISPLAY_REVIEW))) {
198             $displayscore = false;
199         }
200         if (!$options['showscorestudent'] && in_array($mode, array(gradingform_rubric_controller::DISPLAY_VIEW, gradingform_rubric_controller::DISPLAY_PREVIEW_GRADED))) {
201             $displayscore = false;
202         }
203         if ($displayscore) {
204             $scoreclass = 'score';
205             if (isset($level['error_score'])) {
206                 $scoreclass .= ' error';
207             }
208             $leveltemplate .= html_writer::tag('div', get_string('scorepostfix', 'gradingform_rubric', $score), array('class' => $scoreclass));
209         }
210         if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FULL) {
211             $value = get_string('leveldelete', 'gradingform_rubric');
212             $button = html_writer::empty_tag('input', array('type' => 'submit', 'name' => '{NAME}[criteria][{CRITERION-id}][levels][{LEVEL-id}][delete]', 'id' => '{NAME}-criteria-{CRITERION-id}-levels-{LEVEL-id}-delete', 'value' => $value, 'title' => $value, 'tabindex' => -1));
213             $leveltemplate .= html_writer::tag('div', $button, array('class' => 'delete'));
214         }
215         $leveltemplate .= html_writer::end_tag('div'); // .level-wrapper
216         $leveltemplate .= html_writer::end_tag('td'); // .level
218         $leveltemplate = str_replace('{NAME}', $elementname, $leveltemplate);
219         $leveltemplate = str_replace('{CRITERION-id}', $criterionid, $leveltemplate);
220         $leveltemplate = str_replace('{LEVEL-id}', $level['id'], $leveltemplate);
221         return $leveltemplate;
222     }
224     /**
225      * This function returns html code for displaying rubric template (content before and after
226      * criteria list). Depending on $mode it may be the code to edit rubric, to preview the rubric,
227      * to evaluate somebody or to review the evaluation.
228      *
229      * This function is called from display_rubric() to display the whole rubric.
230      *
231      * When overriding this function it is very important to remember that all elements of html
232      * form (in edit or evaluate mode) must have the name $elementname.
233      *
234      * Also JavaScript relies on the class names of elements and when developer changes them
235      * script might stop working.
236      *
237      * @param int $mode rubric display mode see {@link gradingform_rubric_controller}
238      * @param array $options display options for this rubric, defaults are: {@link gradingform_rubric_controller::get_default_options()}
239      * @param string $elementname the name of the form element (in editor mode) or the prefix for div ids (in view mode)
240      * @param string $criteriastr evaluated templates for this rubric's criteria
241      * @return string
242      */
243     protected function rubric_template($mode, $options, $elementname, $criteriastr) {
244         $classsuffix = ''; // CSS suffix for class of the main div. Depends on the mode
245         switch ($mode) {
246             case gradingform_rubric_controller::DISPLAY_EDIT_FULL:
247                 $classsuffix = ' editor editable'; break;
248             case gradingform_rubric_controller::DISPLAY_EDIT_FROZEN:
249                 $classsuffix = ' editor frozen';  break;
250             case gradingform_rubric_controller::DISPLAY_PREVIEW:
251             case gradingform_rubric_controller::DISPLAY_PREVIEW_GRADED:
252                 $classsuffix = ' editor preview';  break;
253             case gradingform_rubric_controller::DISPLAY_EVAL:
254                 $classsuffix = ' evaluate editable'; break;
255             case gradingform_rubric_controller::DISPLAY_EVAL_FROZEN:
256                 $classsuffix = ' evaluate frozen';  break;
257             case gradingform_rubric_controller::DISPLAY_REVIEW:
258                 $classsuffix = ' review';  break;
259             case gradingform_rubric_controller::DISPLAY_VIEW:
260                 $classsuffix = ' view';  break;
261         }
263         $rubrictemplate = html_writer::start_tag('div', array('id' => 'rubric-{NAME}', 'class' => 'clearfix gradingform_rubric'.$classsuffix));
264         $rubrictemplate .= html_writer::tag('table', $criteriastr, array('class' => 'criteria', 'id' => '{NAME}-criteria'));
265         if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FULL) {
266             $value = get_string('addcriterion', 'gradingform_rubric');
267             $input = html_writer::empty_tag('input', array('type' => 'submit', 'name' => '{NAME}[criteria][addcriterion]', 'id' => '{NAME}-criteria-addcriterion', 'value' => $value, 'title' => $value));
268             $rubrictemplate .= html_writer::tag('div', $input, array('class' => 'addcriterion'));
269         }
270         $rubrictemplate .= $this->rubric_edit_options($mode, $options);
271         $rubrictemplate .= html_writer::end_tag('div');
273         return str_replace('{NAME}', $elementname, $rubrictemplate);
274     }
276     /**
277      * Generates html template to view/edit the rubric options. Expression {NAME} is used in
278      * template for the form element name
279      *
280      * @param int $mode rubric display mode see {@link gradingform_rubric_controller}
281      * @param array $options display options for this rubric, defaults are: {@link gradingform_rubric_controller::get_default_options()}
282      * @return string
283      */
284     protected function rubric_edit_options($mode, $options) {
285         if ($mode != gradingform_rubric_controller::DISPLAY_EDIT_FULL
286                 && $mode != gradingform_rubric_controller::DISPLAY_EDIT_FROZEN
287                 && $mode != gradingform_rubric_controller::DISPLAY_PREVIEW) {
288             // Options are displayed only for people who can manage
289             return;
290         }
291         $html = html_writer::start_tag('div', array('class' => 'options'));
292         $html .= html_writer::tag('div', get_string('rubricoptions', 'gradingform_rubric'), array('class' => 'optionsheading'));
293         $attrs = array('type' => 'hidden', 'name' => '{NAME}[options][optionsset]', 'value' => 1);
294         foreach ($options as $option => $value) {
295             $html .= html_writer::start_tag('div', array('class' => 'option '.$option));
296             $attrs = array('name' => '{NAME}[options]['.$option.']', 'id' => '{NAME}-options-'.$option);
297             switch ($option) {
298                 case 'sortlevelsasc':
299                     // Display option as dropdown
300                     $html .= html_writer::label(get_string($option, 'gradingform_rubric'), $attrs['id'], false, array('class' => 'label'));
301                     $value = (int)(!!$value); // make sure $value is either 0 or 1
302                     if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FULL) {
303                         $selectoptions = array(0 => get_string($option.'0', 'gradingform_rubric'), 1 => get_string($option.'1', 'gradingform_rubric'));
304                         $valuestr = html_writer::select($selectoptions, $attrs['name'], $value, false, array('id' => $attrs['id']));
305                         $html .= html_writer::tag('span', $valuestr, array('class' => 'value'));
306                     } else {
307                         $html .= html_writer::tag('span', get_string($option.$value, 'gradingform_rubric'), array('class' => 'value'));
308                         if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FROZEN) {
309                             $html .= html_writer::empty_tag('input', $attrs + array('type' => 'hidden', 'value' => $value));
310                         }
311                     }
312                     break;
313                 default:
314                     if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FROZEN && $value) {
315                         $html .= html_writer::empty_tag('input', $attrs + array('type' => 'hidden', 'value' => $value));
316                     }
317                     // Display option as checkbox
318                     $attrs['type'] = 'checkbox';
319                     $attrs['value'] = 1;
320                     if ($value) {
321                         $attrs['checked'] = 'checked';
322                     }
323                     if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FROZEN || $mode == gradingform_rubric_controller::DISPLAY_PREVIEW) {
324                         $attrs['disabled'] = 'disabled';
325                         unset($attrs['name']);
326                     }
327                     $html .= html_writer::empty_tag('input', $attrs);
328                     $html .= html_writer::tag('label', get_string($option, 'gradingform_rubric'), array('for' => $attrs['id']));
329                     break;
330             }
331             $html .= html_writer::end_tag('div'); // .option
332         }
333         $html .= html_writer::end_tag('div'); // .options
334         return $html;
335     }
337     /**
338      * This function returns html code for displaying rubric. Depending on $mode it may be the code
339      * to edit rubric, to preview the rubric, to evaluate somebody or to review the evaluation.
340      *
341      * It is very unlikely that this function needs to be overriden by theme. It does not produce
342      * any html code, it just prepares data about rubric design and evaluation, adds the CSS
343      * class to elements and calls the functions level_template, criterion_template and
344      * rubric_template
345      *
346      * @param array $criteria data about the rubric design
347      * @param array $options display options for this rubric, defaults are: {@link gradingform_rubric_controller::get_default_options()}
348      * @param int $mode rubric display mode, see {@link gradingform_rubric_controller}
349      * @param string $elementname the name of the form element (in editor mode) or the prefix for div ids (in view mode)
350      * @param array $values evaluation result
351      * @return string
352      */
353     public function display_rubric($criteria, $options, $mode, $elementname = null, $values = null) {
354         $criteriastr = '';
355         $cnt = 0;
356         foreach ($criteria as $id => $criterion) {
357             $criterion['class'] = $this->get_css_class_suffix($cnt++, sizeof($criteria) -1);
358             $criterion['id'] = $id;
359             $levelsstr = '';
360             $levelcnt = 0;
361             if (isset($values['criteria'][$id])) {
362                 $criterionvalue = $values['criteria'][$id];
363             } else {
364                 $criterionvalue = null;
365             }
366             foreach ($criterion['levels'] as $levelid => $level) {
367                 $level['id'] = $levelid;
368                 $level['class'] = $this->get_css_class_suffix($levelcnt++, sizeof($criterion['levels']) -1);
369                 $level['checked'] = (isset($criterionvalue['levelid']) && ((int)$criterionvalue['levelid'] === $levelid));
370                 if ($level['checked'] && ($mode == gradingform_rubric_controller::DISPLAY_EVAL_FROZEN || $mode == gradingform_rubric_controller::DISPLAY_REVIEW || $mode == gradingform_rubric_controller::DISPLAY_VIEW)) {
371                     $level['class'] .= ' checked';
372                     //in mode DISPLAY_EVAL the class 'checked' will be added by JS if it is enabled. If JS is not enabled, the 'checked' class will only confuse
373                 }
374                 if (isset($criterionvalue['savedlevelid']) && ((int)$criterionvalue['savedlevelid'] === $levelid)) {
375                     $level['class'] .= ' currentchecked';
376                 }
377                 $level['tdwidth'] = 100/count($criterion['levels']);
378                 $levelsstr .= $this->level_template($mode, $options, $elementname, $id, $level);
379             }
380             $criteriastr .= $this->criterion_template($mode, $options, $elementname, $criterion, $levelsstr, $criterionvalue);
381         }
382         return $this->rubric_template($mode, $options, $elementname, $criteriastr);
383     }
385     /**
386      * Help function to return CSS class names for element (first/last/even/odd) with leading space
387      *
388      * @param int $idx index of this element in the row/column
389      * @param int $maxidx maximum index of the element in the row/column
390      * @return string
391      */
392     protected function get_css_class_suffix($idx, $maxidx) {
393         $class = '';
394         if ($idx == 0) {
395             $class .= ' first';
396         }
397         if ($idx == $maxidx) {
398             $class .= ' last';
399         }
400         if ($idx%2) {
401             $class .= ' odd';
402         } else {
403             $class .= ' even';
404         }
405         return $class;
406     }
408     /**
409      * Displays for the student the list of instances or default content if no instances found
410      *
411      * @param array $instances array of objects of type gradingform_rubric_instance
412      * @param string $defaultcontent default string that would be displayed without advanced grading
413      * @param boolean $cangrade whether current user has capability to grade in this context
414      * @return string
415      */
416     public function display_instances($instances, $defaultcontent, $cangrade) {
417         $return = '';
418         if (sizeof($instances)) {
419             $return .= html_writer::start_tag('div', array('class' => 'advancedgrade'));
420             $idx = 0;
421             foreach ($instances as $instance) {
422                 $return .= $this->display_instance($instance, $idx++, $cangrade);
423             }
424             $return .= html_writer::end_tag('div');
425         }
426         return $return. $defaultcontent;
427     }
429     /**
430      * Displays one grading instance
431      *
432      * @param gradingform_rubric_instance $instance
433      * @param int $idx unique number of instance on page
434      * @param bool $cangrade whether current user has capability to grade in this context
435      */
436     public function display_instance(gradingform_rubric_instance $instance, $idx, $cangrade) {
437         $criteria = $instance->get_controller()->get_definition()->rubric_criteria;
438         $options = $instance->get_controller()->get_options();
439         $values = $instance->get_rubric_filling();
440         if ($cangrade) {
441             $mode = gradingform_rubric_controller::DISPLAY_REVIEW;
442             $showdescription = $options['showdescriptionteacher'];
443         } else {
444             $mode = gradingform_rubric_controller::DISPLAY_VIEW;
445             $showdescription = $options['showdescriptionstudent'];
446         }
447         $output = '';
448         if ($showdescription) {
449             $output .= $this->box($instance->get_controller()->get_formatted_description(), 'gradingform_rubric-description');
450         }
451         $output .= $this->display_rubric($criteria, $options, $mode, 'rubric'.$idx, $values);
452         return $output;
453     }
455     /**
456      * Displays confirmation that students require re-grading
457      *
458      * @param string $elementname
459      * @param int $changelevel
460      * @param string $value
461      * @return string
462      */
463     public function display_regrade_confirmation($elementname, $changelevel, $value) {
464         $html = html_writer::start_tag('div', array('class' => 'gradingform_rubric-regrade'));
465         if ($changelevel<=2) {
466             $html .= html_writer::label(get_string('regrademessage1', 'gradingform_rubric'), 'menu' . $elementname . 'regrade');
467             $selectoptions = array(
468                 0 => get_string('regradeoption0', 'gradingform_rubric'),
469                 1 => get_string('regradeoption1', 'gradingform_rubric')
470             );
471             $html .= html_writer::select($selectoptions, $elementname.'[regrade]', $value, false);
472         } else {
473             $html .= get_string('regrademessage5', 'gradingform_rubric');
474             $html .= html_writer::empty_tag('input', array('name' => $elementname.'[regrade]', 'value' => 1, 'type' => 'hidden'));
475         }
476         $html .= html_writer::end_tag('div');
477         return $html;
478     }
480     /**
481      * Generates and returns HTML code to display information box about how rubric score is converted to the grade
482      *
483      * @param array $scores
484      * @return string
485      */
486     public function display_rubric_mapping_explained($scores) {
487         $html = '';
488         if (!$scores) {
489             return $html;
490         }
491         $html .= $this->box(
492                 html_writer::tag('h4', get_string('rubricmapping', 'gradingform_rubric')).
493                 html_writer::tag('div', get_string('rubricmappingexplained', 'gradingform_rubric', (object)$scores))
494                 , 'generalbox rubricmappingexplained');
495         return $html;
496     }