MDL-66999 theme_boost: @extend remove extends for grades
[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  * @package    gradingform_rubric
31  * @copyright  2011 Marina Glancy
32  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
33  */
34 class gradingform_rubric_renderer extends plugin_renderer_base {
36     /**
37      * This function returns html code for displaying criterion. Depending on $mode it may be the
38      * code to edit rubric, to preview the rubric, to evaluate somebody or to review the evaluation.
39      *
40      * This function may be called from display_rubric() to display the whole rubric, or it can be
41      * called by itself to return a template used by JavaScript to add new empty criteria to the
42      * rubric being designed.
43      * In this case it will use macros like {NAME}, {LEVELS}, {CRITERION-id}, etc.
44      *
45      * When overriding this function it is very important to remember that all elements of html
46      * form (in edit or evaluate mode) must have the name $elementname.
47      *
48      * Also JavaScript relies on the class names of elements and when developer changes them
49      * script might stop working.
50      *
51      * @param int $mode rubric display mode, see {@link gradingform_rubric_controller}
52      * @param array $options display options for this rubric, defaults are: {@link gradingform_rubric_controller::get_default_options()}
53      * @param string $elementname the name of the form element (in editor mode) or the prefix for div ids (in view mode)
54      * @param array|null $criterion criterion data
55      * @param string $levelsstr evaluated templates for this criterion levels
56      * @param array|null $value (only in view mode) teacher's feedback on this criterion
57      * @return string
58      */
59     public function criterion_template($mode, $options, $elementname = '{NAME}', $criterion = null, $levelsstr = '{LEVELS}', $value = null) {
60         // TODO MDL-31235 description format, remark format
61         if ($criterion === null || !is_array($criterion) || !array_key_exists('id', $criterion)) {
62             $criterion = array('id' => '{CRITERION-id}', 'description' => '{CRITERION-description}', 'sortorder' => '{CRITERION-sortorder}', 'class' => '{CRITERION-class}');
63         } else {
64             foreach (array('sortorder', 'description', 'class') as $key) {
65                 // set missing array elements to empty strings to avoid warnings
66                 if (!array_key_exists($key, $criterion)) {
67                     $criterion[$key] = '';
68                 }
69             }
70         }
71         $criteriontemplate = html_writer::start_tag('tr', array('class' => 'criterion'. $criterion['class'], 'id' => '{NAME}-criteria-{CRITERION-id}'));
72         if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FULL) {
73             $criteriontemplate .= html_writer::start_tag('td', array('class' => 'controls'));
74             foreach (array('moveup', 'delete', 'movedown', 'duplicate') as $key) {
75                 $value = get_string('criterion'.$key, 'gradingform_rubric');
76                 $button = html_writer::empty_tag('input', array('type' => 'submit', 'name' => '{NAME}[criteria][{CRITERION-id}]['.$key.']',
77                     'id' => '{NAME}-criteria-{CRITERION-id}-'.$key, 'value' => $value));
78                 $criteriontemplate .= html_writer::tag('div', $button, array('class' => $key));
79             }
80             $criteriontemplate .= html_writer::empty_tag('input', array('type' => 'hidden',
81                                                                         'name' => '{NAME}[criteria][{CRITERION-id}][sortorder]',
82                                                                         'value' => $criterion['sortorder']));
83             $criteriontemplate .= html_writer::end_tag('td'); // .controls
85             // Criterion description text area.
86             $descriptiontextareaparams = array(
87                 'name' => '{NAME}[criteria][{CRITERION-id}][description]',
88                 'id' => '{NAME}-criteria-{CRITERION-id}-description',
89                 'aria-label' => get_string('criterion', 'gradingform_rubric', ''),
90                 'cols' => '10', 'rows' => '5'
91             );
92             $description = html_writer::tag('textarea', s($criterion['description']), $descriptiontextareaparams);
93         } else {
94             if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FROZEN) {
95                 $criteriontemplate .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => '{NAME}[criteria][{CRITERION-id}][sortorder]', 'value' => $criterion['sortorder']));
96                 $criteriontemplate .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => '{NAME}[criteria][{CRITERION-id}][description]', 'value' => $criterion['description']));
97             }
98             $description = s($criterion['description']);
99         }
100         $descriptionclass = 'description';
101         if (isset($criterion['error_description'])) {
102             $descriptionclass .= ' error';
103         }
105         // Description cell params.
106         $descriptiontdparams = array(
107             'class' => $descriptionclass,
108             'id' => '{NAME}-criteria-{CRITERION-id}-description-cell'
109         );
110         if ($mode != gradingform_rubric_controller::DISPLAY_EDIT_FULL &&
111             $mode != gradingform_rubric_controller::DISPLAY_EDIT_FROZEN) {
112             // Set description's cell as tab-focusable.
113             $descriptiontdparams['tabindex'] = '0';
114             // Set label for the criterion cell.
115             $descriptiontdparams['aria-label'] = get_string('criterion', 'gradingform_rubric', s($criterion['description']));
116         }
118         // Description cell.
119         $criteriontemplate .= html_writer::tag('td', $description, $descriptiontdparams);
121         // Levels table.
122         $levelsrowparams = array('id' => '{NAME}-criteria-{CRITERION-id}-levels');
123         if ($mode != gradingform_rubric_controller::DISPLAY_EDIT_FULL) {
124             $levelsrowparams['role'] = 'radiogroup';
125         }
126         $levelsrow = html_writer::tag('tr', $levelsstr, $levelsrowparams);
128         $levelstableparams = array(
129             'id' => '{NAME}-criteria-{CRITERION-id}-levels-table',
130             'aria-label' => get_string('levelsgroup', 'gradingform_rubric')
131         );
132         $levelsstrtable = html_writer::tag('table', $levelsrow, $levelstableparams);
133         $levelsclass = 'levels';
134         if (isset($criterion['error_levels'])) {
135             $levelsclass .= ' error';
136         }
137         $criteriontemplate .= html_writer::tag('td', $levelsstrtable, array('class' => $levelsclass));
138         if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FULL) {
139             $value = get_string('criterionaddlevel', 'gradingform_rubric');
140             $button = html_writer::empty_tag('input', array('type' => 'submit', 'name' => '{NAME}[criteria][{CRITERION-id}][levels][addlevel]',
141                 'id' => '{NAME}-criteria-{CRITERION-id}-levels-addlevel', 'value' => $value));
142             $criteriontemplate .= html_writer::tag('td', $button, array('class' => 'addlevel'));
143         }
144         $displayremark = ($options['enableremarks'] && ($mode != gradingform_rubric_controller::DISPLAY_VIEW || $options['showremarksstudent']));
145         if ($displayremark) {
146             $currentremark = '';
147             if (isset($value['remark'])) {
148                 $currentremark = $value['remark'];
149             }
151             // Label for criterion remark.
152             $remarkinfo = new stdClass();
153             $remarkinfo->description = s($criterion['description']);
154             $remarkinfo->remark = $currentremark;
155             $remarklabeltext = get_string('criterionremark', 'gradingform_rubric', $remarkinfo);
157             if ($mode == gradingform_rubric_controller::DISPLAY_EVAL) {
158                 // HTML parameters for remarks text area.
159                 $remarkparams = array(
160                     'name' => '{NAME}[criteria][{CRITERION-id}][remark]',
161                     'id' => '{NAME}-criteria-{CRITERION-id}-remark',
162                     'cols' => '10', 'rows' => '5',
163                     'aria-label' => $remarklabeltext
164                 );
165                 $input = html_writer::tag('textarea', s($currentremark), $remarkparams);
166                 $criteriontemplate .= html_writer::tag('td', $input, array('class' => 'remark'));
167             } else if ($mode == gradingform_rubric_controller::DISPLAY_EVAL_FROZEN) {
168                 $criteriontemplate .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => '{NAME}[criteria][{CRITERION-id}][remark]', 'value' => $currentremark));
169             }else if ($mode == gradingform_rubric_controller::DISPLAY_REVIEW || $mode == gradingform_rubric_controller::DISPLAY_VIEW) {
170                 // HTML parameters for remarks cell.
171                 $remarkparams = array(
172                     'class' => 'remark',
173                     'tabindex' => '0',
174                     'id' => '{NAME}-criteria-{CRITERION-id}-remark',
175                     'aria-label' => $remarklabeltext
176                 );
177                 $criteriontemplate .= html_writer::tag('td', s($currentremark), $remarkparams);
178             }
179         }
180         $criteriontemplate .= html_writer::end_tag('tr'); // .criterion
182         $criteriontemplate = str_replace('{NAME}', $elementname, $criteriontemplate);
183         $criteriontemplate = str_replace('{CRITERION-id}', $criterion['id'], $criteriontemplate);
184         return $criteriontemplate;
185     }
187     /**
188      * This function returns html code for displaying one level of one criterion. Depending on $mode
189      * it may be the code to edit rubric, to preview the rubric, to evaluate somebody or to review the evaluation.
190      *
191      * This function may be called from display_rubric() to display the whole rubric, or it can be
192      * called by itself to return a template used by JavaScript to add new empty level to the
193      * criterion during the design of rubric.
194      * In this case it will use macros like {NAME}, {CRITERION-id}, {LEVEL-id}, etc.
195      *
196      * When overriding this function it is very important to remember that all elements of html
197      * form (in edit or evaluate mode) must have the name $elementname.
198      *
199      * Also JavaScript relies on the class names of elements and when developer changes them
200      * script might stop working.
201      *
202      * @param int $mode rubric display mode see {@link gradingform_rubric_controller}
203      * @param array $options display options for this rubric, defaults are: {@link gradingform_rubric_controller::get_default_options()}
204      * @param string $elementname the name of the form element (in editor mode) or the prefix for div ids (in view mode)
205      * @param string|int $criterionid either id of the nesting criterion or a macro for template
206      * @param array|null $level level data, also in view mode it might also have property $level['checked'] whether this level is checked
207      * @return string
208      */
209     public function level_template($mode, $options, $elementname = '{NAME}', $criterionid = '{CRITERION-id}', $level = null) {
210         // TODO MDL-31235 definition format
211         if (!isset($level['id'])) {
212             $level = array('id' => '{LEVEL-id}', 'definition' => '{LEVEL-definition}', 'score' => '{LEVEL-score}', 'class' => '{LEVEL-class}', 'checked' => false);
213         } else {
214             foreach (array('score', 'definition', 'class', 'checked', 'index') as $key) {
215                 // set missing array elements to empty strings to avoid warnings
216                 if (!array_key_exists($key, $level)) {
217                     $level[$key] = '';
218                 }
219             }
220         }
222         // Get level index.
223         $levelindex = isset($level['index']) ? $level['index'] : '{LEVEL-index}';
225         // Template for one level within one criterion
226         $tdattributes = array(
227             'id' => '{NAME}-criteria-{CRITERION-id}-levels-{LEVEL-id}',
228             'class' => 'level' . $level['class']
229         );
230         if (isset($level['tdwidth'])) {
231             $tdattributes['width'] = round($level['tdwidth']).'%';
232         }
234         $leveltemplate = html_writer::start_tag('div', array('class' => 'level-wrapper'));
235         if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FULL) {
236             $definitionparams = array(
237                 'id' => '{NAME}-criteria-{CRITERION-id}-levels-{LEVEL-id}-definition',
238                 'name' => '{NAME}[criteria][{CRITERION-id}][levels][{LEVEL-id}][definition]',
239                 'aria-label' => get_string('leveldefinition', 'gradingform_rubric', $levelindex),
240                 'cols' => '10', 'rows' => '4'
241             );
242             $definition = html_writer::tag('textarea', s($level['definition']), $definitionparams);
244             $scoreparams = array(
245                 'type' => 'text',
246                 'id' => '{NAME}[criteria][{CRITERION-id}][levels][{LEVEL-id}][score]',
247                 'name' => '{NAME}[criteria][{CRITERION-id}][levels][{LEVEL-id}][score]',
248                 'aria-label' => get_string('scoreinputforlevel', 'gradingform_rubric', $levelindex),
249                 'size' => '3',
250                 'value' => $level['score']
251             );
252             $score = html_writer::empty_tag('input', $scoreparams);
253         } else {
254             if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FROZEN) {
255                 $leveltemplate .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => '{NAME}[criteria][{CRITERION-id}][levels][{LEVEL-id}][definition]', 'value' => $level['definition']));
256                 $leveltemplate .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => '{NAME}[criteria][{CRITERION-id}][levels][{LEVEL-id}][score]', 'value' => $level['score']));
257             }
258             $definition = s($level['definition']);
259             $score = $level['score'];
260         }
261         if ($mode == gradingform_rubric_controller::DISPLAY_EVAL) {
262             $levelradioparams = array(
263                 'type' => 'radio',
264                 'id' => '{NAME}-criteria-{CRITERION-id}-levels-{LEVEL-id}-definition',
265                 'name' => '{NAME}[criteria][{CRITERION-id}][levelid]',
266                 'value' => $level['id']
267             );
268             if ($level['checked']) {
269                 $levelradioparams['checked'] = 'checked';
270             }
271             $input = html_writer::empty_tag('input', $levelradioparams);
272             $leveltemplate .= html_writer::div($input, 'radio');
273         }
274         if ($mode == gradingform_rubric_controller::DISPLAY_EVAL_FROZEN && $level['checked']) {
275             $leveltemplate .= html_writer::empty_tag('input',
276                 array(
277                     'type' => 'hidden',
278                     'name' => '{NAME}[criteria][{CRITERION-id}][levelid]',
279                     'value' => $level['id']
280                 )
281             );
282         }
283         $score = html_writer::tag('span', $score, array('id' => '{NAME}-criteria-{CRITERION-id}-levels-{LEVEL-id}-score', 'class' => 'scorevalue'));
284         $definitionclass = 'definition';
285         if (isset($level['error_definition'])) {
286             $definitionclass .= ' error';
287         }
289         if ($mode != gradingform_rubric_controller::DISPLAY_EDIT_FULL &&
290             $mode != gradingform_rubric_controller::DISPLAY_EDIT_FROZEN) {
292             $tdattributes['tabindex'] = '0';
293             $levelinfo = new stdClass();
294             $levelinfo->definition = s($level['definition']);
295             $levelinfo->score = $level['score'];
296             $tdattributes['aria-label'] = get_string('level', 'gradingform_rubric', $levelinfo);
298             if ($mode != gradingform_rubric_controller::DISPLAY_PREVIEW &&
299                 $mode != gradingform_rubric_controller::DISPLAY_PREVIEW_GRADED) {
300                 // Add role of radio button to level cell if not in edit and preview mode.
301                 $tdattributes['role'] = 'radio';
302                 if ($level['checked']) {
303                     $tdattributes['aria-checked'] = 'true';
304                 } else {
305                     $tdattributes['aria-checked'] = 'false';
306                 }
307             }
308         }
310         $leveltemplateparams = array(
311             'id' => '{NAME}-criteria-{CRITERION-id}-levels-{LEVEL-id}-definition-container'
312         );
313         $leveltemplate .= html_writer::div($definition, $definitionclass, $leveltemplateparams);
314         $displayscore = true;
315         if (!$options['showscoreteacher'] && in_array($mode, array(gradingform_rubric_controller::DISPLAY_EVAL, gradingform_rubric_controller::DISPLAY_EVAL_FROZEN, gradingform_rubric_controller::DISPLAY_REVIEW))) {
316             $displayscore = false;
317         }
318         if (!$options['showscorestudent'] && in_array($mode, array(gradingform_rubric_controller::DISPLAY_VIEW, gradingform_rubric_controller::DISPLAY_PREVIEW_GRADED))) {
319             $displayscore = false;
320         }
321         if ($displayscore) {
322             $scoreclass = 'score';
323             if (isset($level['error_score'])) {
324                 $scoreclass .= ' error';
325             }
326             $leveltemplate .= html_writer::tag('div', get_string('scorepostfix', 'gradingform_rubric', $score), array('class' => $scoreclass));
327         }
328         if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FULL) {
329             $value = get_string('leveldelete', 'gradingform_rubric', $levelindex);
330             $buttonparams = array(
331                 'type' => 'submit',
332                 'name' => '{NAME}[criteria][{CRITERION-id}][levels][{LEVEL-id}][delete]',
333                 'id' => '{NAME}-criteria-{CRITERION-id}-levels-{LEVEL-id}-delete',
334                 'value' => $value
335             );
336             $button = html_writer::empty_tag('input', $buttonparams);
337             $leveltemplate .= html_writer::tag('div', $button, array('class' => 'delete'));
338         }
339         $leveltemplate .= html_writer::end_tag('div'); // .level-wrapper
341         $leveltemplate = html_writer::tag('td', $leveltemplate, $tdattributes); // The .level cell.
343         $leveltemplate = str_replace('{NAME}', $elementname, $leveltemplate);
344         $leveltemplate = str_replace('{CRITERION-id}', $criterionid, $leveltemplate);
345         $leveltemplate = str_replace('{LEVEL-id}', $level['id'], $leveltemplate);
346         return $leveltemplate;
347     }
349     /**
350      * This function returns html code for displaying rubric template (content before and after
351      * criteria list). Depending on $mode it may be the code to edit rubric, to preview the rubric,
352      * to evaluate somebody or to review the evaluation.
353      *
354      * This function is called from display_rubric() to display the whole rubric.
355      *
356      * When overriding this function it is very important to remember that all elements of html
357      * form (in edit or evaluate mode) must have the name $elementname.
358      *
359      * Also JavaScript relies on the class names of elements and when developer changes them
360      * script might stop working.
361      *
362      * @param int $mode rubric display mode see {@link gradingform_rubric_controller}
363      * @param array $options display options for this rubric, defaults are: {@link gradingform_rubric_controller::get_default_options()}
364      * @param string $elementname the name of the form element (in editor mode) or the prefix for div ids (in view mode)
365      * @param string $criteriastr evaluated templates for this rubric's criteria
366      * @return string
367      */
368     protected function rubric_template($mode, $options, $elementname, $criteriastr) {
369         $classsuffix = ''; // CSS suffix for class of the main div. Depends on the mode
370         switch ($mode) {
371             case gradingform_rubric_controller::DISPLAY_EDIT_FULL:
372                 $classsuffix = ' editor editable'; break;
373             case gradingform_rubric_controller::DISPLAY_EDIT_FROZEN:
374                 $classsuffix = ' editor frozen';  break;
375             case gradingform_rubric_controller::DISPLAY_PREVIEW:
376             case gradingform_rubric_controller::DISPLAY_PREVIEW_GRADED:
377                 $classsuffix = ' editor preview';  break;
378             case gradingform_rubric_controller::DISPLAY_EVAL:
379                 $classsuffix = ' evaluate editable'; break;
380             case gradingform_rubric_controller::DISPLAY_EVAL_FROZEN:
381                 $classsuffix = ' evaluate frozen';  break;
382             case gradingform_rubric_controller::DISPLAY_REVIEW:
383                 $classsuffix = ' review';  break;
384             case gradingform_rubric_controller::DISPLAY_VIEW:
385                 $classsuffix = ' view';  break;
386         }
388         $rubrictemplate = html_writer::start_tag('div', array('id' => 'rubric-{NAME}', 'class' => 'clearfix gradingform_rubric'.$classsuffix));
390         // Rubric table.
391         $rubrictableparams = array(
392             'class' => 'criteria',
393             'id' => '{NAME}-criteria',
394             'aria-label' => get_string('rubric', 'gradingform_rubric'));
395         $rubrictable = html_writer::tag('table', $criteriastr, $rubrictableparams);
396         $rubrictemplate .= $rubrictable;
397         if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FULL) {
398             $value = get_string('addcriterion', 'gradingform_rubric');
399             $criteriainputparams = array(
400                 'type' => 'submit',
401                 'name' => '{NAME}[criteria][addcriterion]',
402                 'id' => '{NAME}-criteria-addcriterion',
403                 'value' => $value
404             );
405             $input = html_writer::empty_tag('input', $criteriainputparams);
406             $rubrictemplate .= html_writer::tag('div', $input, array('class' => 'addcriterion btn btn-secondary'));
407         }
408         $rubrictemplate .= $this->rubric_edit_options($mode, $options);
409         $rubrictemplate .= html_writer::end_tag('div');
411         return str_replace('{NAME}', $elementname, $rubrictemplate);
412     }
414     /**
415      * Generates html template to view/edit the rubric options. Expression {NAME} is used in
416      * template for the form element name
417      *
418      * @param int $mode rubric display mode see {@link gradingform_rubric_controller}
419      * @param array $options display options for this rubric, defaults are: {@link gradingform_rubric_controller::get_default_options()}
420      * @return string
421      */
422     protected function rubric_edit_options($mode, $options) {
423         if ($mode != gradingform_rubric_controller::DISPLAY_EDIT_FULL
424                 && $mode != gradingform_rubric_controller::DISPLAY_EDIT_FROZEN
425                 && $mode != gradingform_rubric_controller::DISPLAY_PREVIEW) {
426             // Options are displayed only for people who can manage
427             return;
428         }
429         $html = html_writer::start_tag('div', array('class' => 'options'));
430         $html .= html_writer::tag('div', get_string('rubricoptions', 'gradingform_rubric'), array('class' => 'optionsheading'));
431         $attrs = array('type' => 'hidden', 'name' => '{NAME}[options][optionsset]', 'value' => 1);
432         foreach ($options as $option => $value) {
433             $html .= html_writer::start_tag('div', array('class' => 'option '.$option));
434             $attrs = array('name' => '{NAME}[options]['.$option.']', 'id' => '{NAME}-options-'.$option);
435             switch ($option) {
436                 case 'sortlevelsasc':
437                     // Display option as dropdown
438                     $html .= html_writer::label(get_string($option, 'gradingform_rubric'), $attrs['id'], false);
439                     $value = (int)(!!$value); // make sure $value is either 0 or 1
440                     if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FULL) {
441                         $selectoptions = array(0 => get_string($option.'0', 'gradingform_rubric'), 1 => get_string($option.'1', 'gradingform_rubric'));
442                         $valuestr = html_writer::select($selectoptions, $attrs['name'], $value, false, array('id' => $attrs['id']));
443                         $html .= html_writer::tag('span', $valuestr, array('class' => 'value'));
444                     } else {
445                         $html .= html_writer::tag('span', get_string($option.$value, 'gradingform_rubric'), array('class' => 'value'));
446                         if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FROZEN) {
447                             $html .= html_writer::empty_tag('input', $attrs + array('type' => 'hidden', 'value' => $value));
448                         }
449                     }
450                     break;
451                 default:
452                     if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FROZEN && $value) {
453                         // Id should be different then the actual input added later.
454                         $attrs['id'] .= '_hidden';
455                         $html .= html_writer::empty_tag('input', $attrs + array('type' => 'hidden', 'value' => $value));
456                     }
457                     // Display option as checkbox
458                     $attrs['type'] = 'checkbox';
459                     $attrs['value'] = 1;
460                     if ($value) {
461                         $attrs['checked'] = 'checked';
462                     }
463                     if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FROZEN || $mode == gradingform_rubric_controller::DISPLAY_PREVIEW) {
464                         $attrs['disabled'] = 'disabled';
465                         unset($attrs['name']);
466                         // Id should be different then the actual input added later.
467                         $attrs['id'] .= '_disabled';
468                     }
469                     $html .= html_writer::empty_tag('input', $attrs);
470                     $html .= html_writer::tag('label', get_string($option, 'gradingform_rubric'), array('for' => $attrs['id']));
471                     break;
472             }
473             if (get_string_manager()->string_exists($option.'_help', 'gradingform_rubric')) {
474                 $html .= $this->help_icon($option, 'gradingform_rubric');
475             }
476             $html .= html_writer::end_tag('div'); // .option
477         }
478         $html .= html_writer::end_tag('div'); // .options
479         return $html;
480     }
482     /**
483      * This function returns html code for displaying rubric. Depending on $mode it may be the code
484      * to edit rubric, to preview the rubric, to evaluate somebody or to review the evaluation.
485      *
486      * It is very unlikely that this function needs to be overriden by theme. It does not produce
487      * any html code, it just prepares data about rubric design and evaluation, adds the CSS
488      * class to elements and calls the functions level_template, criterion_template and
489      * rubric_template
490      *
491      * @param array $criteria data about the rubric design
492      * @param array $options display options for this rubric, defaults are: {@link gradingform_rubric_controller::get_default_options()}
493      * @param int $mode rubric display mode, see {@link gradingform_rubric_controller}
494      * @param string $elementname the name of the form element (in editor mode) or the prefix for div ids (in view mode)
495      * @param array $values evaluation result
496      * @return string
497      */
498     public function display_rubric($criteria, $options, $mode, $elementname = null, $values = null) {
499         $criteriastr = '';
500         $cnt = 0;
501         foreach ($criteria as $id => $criterion) {
502             $criterion['class'] = $this->get_css_class_suffix($cnt++, sizeof($criteria) -1);
503             $criterion['id'] = $id;
504             $levelsstr = '';
505             $levelcnt = 0;
506             if (isset($values['criteria'][$id])) {
507                 $criterionvalue = $values['criteria'][$id];
508             } else {
509                 $criterionvalue = null;
510             }
511             $index = 1;
512             foreach ($criterion['levels'] as $levelid => $level) {
513                 $level['id'] = $levelid;
514                 $level['class'] = $this->get_css_class_suffix($levelcnt++, sizeof($criterion['levels']) -1);
515                 $level['checked'] = (isset($criterionvalue['levelid']) && ((int)$criterionvalue['levelid'] === $levelid));
516                 if ($level['checked'] && ($mode == gradingform_rubric_controller::DISPLAY_EVAL_FROZEN || $mode == gradingform_rubric_controller::DISPLAY_REVIEW || $mode == gradingform_rubric_controller::DISPLAY_VIEW)) {
517                     $level['class'] .= ' checked';
518                     //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
519                 }
520                 if (isset($criterionvalue['savedlevelid']) && ((int)$criterionvalue['savedlevelid'] === $levelid)) {
521                     $level['class'] .= ' currentchecked';
522                 }
523                 $level['tdwidth'] = 100/count($criterion['levels']);
524                 $level['index'] = $index;
525                 $levelsstr .= $this->level_template($mode, $options, $elementname, $id, $level);
526                 $index++;
527             }
528             $criteriastr .= $this->criterion_template($mode, $options, $elementname, $criterion, $levelsstr, $criterionvalue);
529         }
530         return $this->rubric_template($mode, $options, $elementname, $criteriastr);
531     }
533     /**
534      * Help function to return CSS class names for element (first/last/even/odd) with leading space
535      *
536      * @param int $idx index of this element in the row/column
537      * @param int $maxidx maximum index of the element in the row/column
538      * @return string
539      */
540     protected function get_css_class_suffix($idx, $maxidx) {
541         $class = '';
542         if ($idx == 0) {
543             $class .= ' first';
544         }
545         if ($idx == $maxidx) {
546             $class .= ' last';
547         }
548         if ($idx%2) {
549             $class .= ' odd';
550         } else {
551             $class .= ' even';
552         }
553         return $class;
554     }
556     /**
557      * Displays for the student the list of instances or default content if no instances found
558      *
559      * @param array $instances array of objects of type gradingform_rubric_instance
560      * @param string $defaultcontent default string that would be displayed without advanced grading
561      * @param boolean $cangrade whether current user has capability to grade in this context
562      * @return string
563      */
564     public function display_instances($instances, $defaultcontent, $cangrade) {
565         $return = '';
566         if (sizeof($instances)) {
567             $return .= html_writer::start_tag('div', array('class' => 'advancedgrade'));
568             $idx = 0;
569             foreach ($instances as $instance) {
570                 $return .= $this->display_instance($instance, $idx++, $cangrade);
571             }
572             $return .= html_writer::end_tag('div');
573         }
574         return $return. $defaultcontent;
575     }
577     /**
578      * Displays one grading instance
579      *
580      * @param gradingform_rubric_instance $instance
581      * @param int $idx unique number of instance on page
582      * @param bool $cangrade whether current user has capability to grade in this context
583      */
584     public function display_instance(gradingform_rubric_instance $instance, $idx, $cangrade) {
585         $criteria = $instance->get_controller()->get_definition()->rubric_criteria;
586         $options = $instance->get_controller()->get_options();
587         $values = $instance->get_rubric_filling();
588         if ($cangrade) {
589             $mode = gradingform_rubric_controller::DISPLAY_REVIEW;
590             $showdescription = $options['showdescriptionteacher'];
591         } else {
592             $mode = gradingform_rubric_controller::DISPLAY_VIEW;
593             $showdescription = $options['showdescriptionstudent'];
594         }
595         $output = '';
596         if ($showdescription) {
597             $output .= $this->box($instance->get_controller()->get_formatted_description(), 'gradingform_rubric-description');
598         }
599         $output .= $this->display_rubric($criteria, $options, $mode, 'rubric'.$idx, $values);
600         return $output;
601     }
603     /**
604      * Displays confirmation that students require re-grading
605      *
606      * @param string $elementname
607      * @param int $changelevel
608      * @param string $value
609      * @return string
610      */
611     public function display_regrade_confirmation($elementname, $changelevel, $value) {
612         $html = html_writer::start_tag('div', array('class' => 'gradingform_rubric-regrade', 'role' => 'alert'));
613         if ($changelevel<=2) {
614             $html .= html_writer::label(get_string('regrademessage1', 'gradingform_rubric'), 'menu' . $elementname . 'regrade');
615             $selectoptions = array(
616                 0 => get_string('regradeoption0', 'gradingform_rubric'),
617                 1 => get_string('regradeoption1', 'gradingform_rubric')
618             );
619             $html .= html_writer::select($selectoptions, $elementname.'[regrade]', $value, false);
620         } else {
621             $html .= get_string('regrademessage5', 'gradingform_rubric');
622             $html .= html_writer::empty_tag('input', array('name' => $elementname.'[regrade]', 'value' => 1, 'type' => 'hidden'));
623         }
624         $html .= html_writer::end_tag('div');
625         return $html;
626     }
628     /**
629      * Generates and returns HTML code to display information box about how rubric score is converted to the grade
630      *
631      * @param array $scores
632      * @return string
633      */
634     public function display_rubric_mapping_explained($scores) {
635         $html = '';
636         if (!$scores) {
637             return $html;
638         }
639         if ($scores['minscore'] <> 0) {
640             $html .= $this->output->notification(get_string('zerolevelsabsent', 'gradingform_rubric'), 'error');
641         }
642         $html .= $this->output->notification(get_string('rubricmappingexplained', 'gradingform_rubric', (object)$scores), 'info');
643         return $html;
644     }