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