Proyectos de Subversion Moodle

Rev

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

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
/**
18
 * 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
 */
24
 
25
defined('MOODLE_INTERNAL') || die();
26
 
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 {
35
 
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
84
 
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
        }
104
 
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
        }
117
 
1441 ariadna 118
        // Default value for criterion ids.
119
        // Edge case: submitting empty grade when remark field is disabled.
120
        // Reason: we need the criteria keys for the clear_attempt to clear the rubric fillings.
121
        if ($mode == gradingform_rubric_controller::DISPLAY_EVAL) {
122
            $criteriontemplate .= html_writer::empty_tag('input', [
123
                'type' => 'hidden',
124
                'name' => '{NAME}[criteria][{CRITERION-id}][]',
125
            ]);
126
        }
127
 
1 efrain 128
        // Description cell.
129
        $criteriontemplate .= html_writer::tag('td', $description, $descriptiontdparams);
130
 
131
        // Levels table.
132
        $levelsrowparams = [
133
            'id' => '{NAME}-criteria-{CRITERION-id}-levels',
134
            'aria-label' => get_string('levelsgroup', 'gradingform_rubric'),
135
        ];
136
        // Add radiogroup role only when not previewing or editing.
137
        $isradiogroup = !in_array($mode, [
138
            gradingform_rubric_controller::DISPLAY_EDIT_FULL,
139
            gradingform_rubric_controller::DISPLAY_EDIT_FROZEN,
140
            gradingform_rubric_controller::DISPLAY_PREVIEW,
141
            gradingform_rubric_controller::DISPLAY_PREVIEW_GRADED,
142
        ]);
143
        $levelsrowparams['role'] = $isradiogroup ? 'radiogroup' : 'list';
144
        $levelsrow = html_writer::tag('tr', $levelsstr, $levelsrowparams);
145
 
146
        $levelstableparams = [
147
            'id' => '{NAME}-criteria-{CRITERION-id}-levels-table',
148
            'role' => 'none',
149
        ];
150
        $levelsstrtable = html_writer::tag('table', $levelsrow, $levelstableparams);
151
        $levelsclass = 'levels';
152
        if (isset($criterion['error_levels'])) {
153
            $levelsclass .= ' error';
154
        }
155
        $criteriontemplate .= html_writer::tag('td', $levelsstrtable, array('class' => $levelsclass));
156
        if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FULL) {
157
            $value = get_string('criterionaddlevel', 'gradingform_rubric');
158
            $button = html_writer::empty_tag('input', array('type' => 'submit', 'name' => '{NAME}[criteria][{CRITERION-id}][levels][addlevel]',
159
                'id' => '{NAME}-criteria-{CRITERION-id}-levels-addlevel', 'value' => $value, 'class' => 'btn btn-secondary'));
160
            $criteriontemplate .= html_writer::tag('td', $button, array('class' => 'addlevel'));
161
        }
162
        $displayremark = ($options['enableremarks'] && ($mode != gradingform_rubric_controller::DISPLAY_VIEW || $options['showremarksstudent']));
163
        if ($displayremark) {
164
            $currentremark = '';
165
            if (isset($value['remark'])) {
166
                $currentremark = $value['remark'];
167
            }
168
 
169
            // Label for criterion remark.
170
            $remarkinfo = new stdClass();
171
            $remarkinfo->description = s($criterion['description']);
172
            $remarkinfo->remark = $currentremark;
173
            $remarklabeltext = get_string('criterionremark', 'gradingform_rubric', $remarkinfo);
174
 
175
            if ($mode == gradingform_rubric_controller::DISPLAY_EVAL) {
176
                // HTML parameters for remarks text area.
177
                $remarkparams = array(
178
                    'name' => '{NAME}[criteria][{CRITERION-id}][remark]',
179
                    'id' => '{NAME}-criteria-{CRITERION-id}-remark',
180
                    'cols' => '10', 'rows' => '5',
181
                    'aria-label' => $remarklabeltext
182
                );
183
                $input = html_writer::tag('textarea', s($currentremark), $remarkparams);
184
                $criteriontemplate .= html_writer::tag('td', $input, array('class' => 'remark'));
185
            } else if ($mode == gradingform_rubric_controller::DISPLAY_EVAL_FROZEN) {
186
                $criteriontemplate .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => '{NAME}[criteria][{CRITERION-id}][remark]', 'value' => $currentremark));
187
            }else if ($mode == gradingform_rubric_controller::DISPLAY_REVIEW || $mode == gradingform_rubric_controller::DISPLAY_VIEW) {
188
                // HTML parameters for remarks cell.
189
                $remarkparams = array(
190
                    'class' => 'remark',
191
                    'tabindex' => '0',
192
                    'id' => '{NAME}-criteria-{CRITERION-id}-remark',
193
                    'aria-label' => $remarklabeltext
194
                );
195
                $criteriontemplate .= html_writer::tag('td', s($currentremark), $remarkparams);
196
            }
197
        }
198
        $criteriontemplate .= html_writer::end_tag('tr'); // .criterion
199
 
200
        $criteriontemplate = str_replace('{NAME}', $elementname, $criteriontemplate);
201
        $criteriontemplate = str_replace('{CRITERION-id}', $criterion['id'], $criteriontemplate);
202
        return $criteriontemplate;
203
    }
204
 
205
    /**
206
     * This function returns html code for displaying one level of one criterion. Depending on $mode
207
     * it may be the code to edit rubric, to preview the rubric, to evaluate somebody or to review the evaluation.
208
     *
209
     * This function may be called from display_rubric() to display the whole rubric, or it can be
210
     * called by itself to return a template used by JavaScript to add new empty level to the
211
     * criterion during the design of rubric.
212
     * In this case it will use macros like {NAME}, {CRITERION-id}, {LEVEL-id}, etc.
213
     *
214
     * When overriding this function it is very important to remember that all elements of html
215
     * form (in edit or evaluate mode) must have the name $elementname.
216
     *
217
     * Also JavaScript relies on the class names of elements and when developer changes them
218
     * script might stop working.
219
     *
220
     * @param int $mode rubric display mode see {@link gradingform_rubric_controller}
221
     * @param array $options display options for this rubric, defaults are: {@link gradingform_rubric_controller::get_default_options()}
222
     * @param string $elementname the name of the form element (in editor mode) or the prefix for div ids (in view mode)
223
     * @param string|int $criterionid either id of the nesting criterion or a macro for template
224
     * @param array|null $level level data, also in view mode it might also have property $level['checked'] whether this level is checked
225
     * @return string
226
     */
227
    public function level_template($mode, $options, $elementname = '{NAME}', $criterionid = '{CRITERION-id}', $level = null) {
228
        // TODO MDL-31235 definition format
229
        if (!isset($level['id'])) {
230
            $level = array('id' => '{LEVEL-id}', 'definition' => '{LEVEL-definition}', 'score' => '{LEVEL-score}', 'class' => '{LEVEL-class}', 'checked' => false);
231
        } else {
232
            foreach (array('score', 'definition', 'class', 'checked', 'index') as $key) {
233
                // set missing array elements to empty strings to avoid warnings
234
                if (!array_key_exists($key, $level)) {
235
                    $level[$key] = '';
236
                }
237
            }
238
        }
239
 
240
        // Get level index.
241
        $levelindex = isset($level['index']) ? $level['index'] : '{LEVEL-index}';
242
 
243
        // Template for one level within one criterion
244
        $tdattributes = array(
245
            'id' => '{NAME}-criteria-{CRITERION-id}-levels-{LEVEL-id}',
246
            'class' => 'text-break level' . $level['class']
247
        );
248
        if (isset($level['tdwidth'])) {
249
            $tdattributes['style'] = "width: " . round($level['tdwidth']).'%;';
250
        }
251
 
252
        $leveltemplate = html_writer::start_tag('div', array('class' => 'level-wrapper'));
253
        if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FULL) {
254
            $definitionparams = array(
255
                'id' => '{NAME}-criteria-{CRITERION-id}-levels-{LEVEL-id}-definition',
256
                'name' => '{NAME}[criteria][{CRITERION-id}][levels][{LEVEL-id}][definition]',
257
                'aria-label' => get_string('leveldefinition', 'gradingform_rubric', $levelindex),
258
                'cols' => '10', 'rows' => '4'
259
            );
260
            $definition = html_writer::tag('textarea', s($level['definition']), $definitionparams);
261
 
262
            $scoreparams = array(
263
                'type' => 'text',
264
                'id' => '{NAME}[criteria][{CRITERION-id}][levels][{LEVEL-id}][score]',
265
                'name' => '{NAME}[criteria][{CRITERION-id}][levels][{LEVEL-id}][score]',
266
                'aria-label' => get_string('scoreinputforlevel', 'gradingform_rubric', $levelindex),
267
                'size' => '3',
268
                'value' => $level['score']
269
            );
270
            $score = html_writer::empty_tag('input', $scoreparams);
271
        } else {
272
            if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FROZEN) {
273
                $leveltemplate .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => '{NAME}[criteria][{CRITERION-id}][levels][{LEVEL-id}][definition]', 'value' => $level['definition']));
274
                $leveltemplate .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => '{NAME}[criteria][{CRITERION-id}][levels][{LEVEL-id}][score]', 'value' => $level['score']));
275
            }
276
            $definition = s($level['definition']);
277
            $score = $level['score'];
278
        }
279
        if ($mode == gradingform_rubric_controller::DISPLAY_EVAL) {
280
            $levelradioparams = array(
281
                'type' => 'radio',
282
                'id' => '{NAME}-criteria-{CRITERION-id}-levels-{LEVEL-id}-definition',
283
                'name' => '{NAME}[criteria][{CRITERION-id}][levelid]',
284
                'value' => $level['id']
285
            );
286
            if ($level['checked']) {
287
                $levelradioparams['checked'] = 'checked';
288
            }
289
            $input = html_writer::empty_tag('input', $levelradioparams);
290
            $leveltemplate .= html_writer::div($input, 'radio');
291
        }
292
        if ($mode == gradingform_rubric_controller::DISPLAY_EVAL_FROZEN && $level['checked']) {
293
            $leveltemplate .= html_writer::empty_tag('input',
294
                array(
295
                    'type' => 'hidden',
296
                    'name' => '{NAME}[criteria][{CRITERION-id}][levelid]',
297
                    'value' => $level['id']
298
                )
299
            );
300
        }
301
        $score = html_writer::tag('span', $score, array('id' => '{NAME}-criteria-{CRITERION-id}-levels-{LEVEL-id}-score', 'class' => 'scorevalue'));
302
        $definitionclass = 'definition';
303
        if (isset($level['error_definition'])) {
304
            $definitionclass .= ' error';
305
        }
306
 
307
        if ($mode != gradingform_rubric_controller::DISPLAY_EDIT_FULL &&
308
            $mode != gradingform_rubric_controller::DISPLAY_EDIT_FROZEN) {
309
 
310
            $tdattributes['tabindex'] = '0';
311
            $levelinfo = new stdClass();
312
            $levelinfo->definition = s($level['definition']);
313
            $levelinfo->score = $level['score'];
314
            $tdattributes['aria-label'] = get_string('level', 'gradingform_rubric', $levelinfo);
315
 
316
            if ($mode != gradingform_rubric_controller::DISPLAY_PREVIEW &&
317
                $mode != gradingform_rubric_controller::DISPLAY_PREVIEW_GRADED) {
318
                // Add role of radio button to level cell if not in edit and preview mode.
319
                $tdattributes['role'] = 'radio';
320
                if ($level['checked']) {
321
                    $tdattributes['aria-checked'] = 'true';
322
                } else {
323
                    $tdattributes['aria-checked'] = 'false';
324
                }
325
            } else {
326
                $tdattributes['role'] = 'listitem';
327
            }
328
        } else {
329
            $tdattributes['role'] = 'listitem';
330
        }
331
 
332
        $leveltemplateparams = array(
333
            'id' => '{NAME}-criteria-{CRITERION-id}-levels-{LEVEL-id}-definition-container'
334
        );
335
        $leveltemplate .= html_writer::div($definition, $definitionclass, $leveltemplateparams);
336
        $displayscore = true;
337
        if (!$options['showscoreteacher'] && in_array($mode, array(gradingform_rubric_controller::DISPLAY_EVAL, gradingform_rubric_controller::DISPLAY_EVAL_FROZEN, gradingform_rubric_controller::DISPLAY_REVIEW))) {
338
            $displayscore = false;
339
        }
340
        if (!$options['showscorestudent'] && in_array($mode, array(gradingform_rubric_controller::DISPLAY_VIEW, gradingform_rubric_controller::DISPLAY_PREVIEW_GRADED))) {
341
            $displayscore = false;
342
        }
343
        if ($displayscore) {
344
            $scoreclass = 'score d-inline';
345
            if (isset($level['error_score'])) {
346
                $scoreclass .= ' error';
347
            }
348
            $leveltemplate .= html_writer::tag('div', get_string('scorepostfix', 'gradingform_rubric', $score), array('class' => $scoreclass));
349
        }
350
        if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FULL) {
351
            $value = get_string('leveldelete', 'gradingform_rubric', $levelindex);
352
            $buttonparams = array(
353
                'type' => 'submit',
354
                'name' => '{NAME}[criteria][{CRITERION-id}][levels][{LEVEL-id}][delete]',
355
                'id' => '{NAME}-criteria-{CRITERION-id}-levels-{LEVEL-id}-delete',
356
                'value' => $value
357
            );
358
            $button = html_writer::empty_tag('input', $buttonparams);
359
            $leveltemplate .= html_writer::tag('div', $button, array('class' => 'delete'));
360
        }
361
        $leveltemplate .= html_writer::end_tag('div'); // .level-wrapper
362
 
363
        $leveltemplate = html_writer::tag('td', $leveltemplate, $tdattributes); // The .level cell.
364
 
365
        $leveltemplate = str_replace('{NAME}', $elementname, $leveltemplate);
366
        $leveltemplate = str_replace('{CRITERION-id}', $criterionid, $leveltemplate);
367
        $leveltemplate = str_replace('{LEVEL-id}', $level['id'], $leveltemplate);
368
        return $leveltemplate;
369
    }
370
 
371
    /**
372
     * This function returns html code for displaying rubric template (content before and after
373
     * criteria list). Depending on $mode it may be the code to edit rubric, to preview the rubric,
374
     * to evaluate somebody or to review the evaluation.
375
     *
376
     * This function is called from display_rubric() to display the whole rubric.
377
     *
378
     * When overriding this function it is very important to remember that all elements of html
379
     * form (in edit or evaluate mode) must have the name $elementname.
380
     *
381
     * Also JavaScript relies on the class names of elements and when developer changes them
382
     * script might stop working.
383
     *
384
     * @param int $mode rubric display mode see {@link gradingform_rubric_controller}
385
     * @param array $options display options for this rubric, defaults are: {@link gradingform_rubric_controller::get_default_options()}
386
     * @param string $elementname the name of the form element (in editor mode) or the prefix for div ids (in view mode)
387
     * @param string $criteriastr evaluated templates for this rubric's criteria
388
     * @return string
389
     */
390
    protected function rubric_template($mode, $options, $elementname, $criteriastr) {
391
        $classsuffix = ''; // CSS suffix for class of the main div. Depends on the mode
392
        switch ($mode) {
393
            case gradingform_rubric_controller::DISPLAY_EDIT_FULL:
394
                $classsuffix = ' editor editable'; break;
395
            case gradingform_rubric_controller::DISPLAY_EDIT_FROZEN:
396
                $classsuffix = ' editor frozen';  break;
397
            case gradingform_rubric_controller::DISPLAY_PREVIEW:
398
            case gradingform_rubric_controller::DISPLAY_PREVIEW_GRADED:
399
                $classsuffix = ' editor preview';  break;
400
            case gradingform_rubric_controller::DISPLAY_EVAL:
401
                $classsuffix = ' evaluate editable'; break;
402
            case gradingform_rubric_controller::DISPLAY_EVAL_FROZEN:
403
                $classsuffix = ' evaluate frozen';  break;
404
            case gradingform_rubric_controller::DISPLAY_REVIEW:
405
                $classsuffix = ' review';  break;
406
            case gradingform_rubric_controller::DISPLAY_VIEW:
407
                $classsuffix = ' view';  break;
408
        }
409
 
410
        $rubrictemplate = html_writer::start_tag('div', array('id' => 'rubric-{NAME}', 'class' => 'clearfix gradingform_rubric'.$classsuffix));
411
 
412
        // Rubric table.
413
        $rubrictableparams = [
414
            'class' => 'criteria',
415
            'id' => '{NAME}-criteria',
416
        ];
1441 ariadna 417
        $caption = html_writer::tag('caption', get_string('rubric', 'gradingform_rubric'), ['class' => 'visually-hidden']);
1 efrain 418
        $rubrictable = html_writer::tag('table', $caption . $criteriastr, $rubrictableparams);
419
        $rubrictemplate .= $rubrictable;
420
        if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FULL) {
421
            $value = get_string('addcriterion', 'gradingform_rubric');
422
            $criteriainputparams = array(
423
                'type' => 'submit',
424
                'name' => '{NAME}[criteria][addcriterion]',
425
                'id' => '{NAME}-criteria-addcriterion',
426
                'value' => $value
427
            );
428
            $input = html_writer::empty_tag('input', $criteriainputparams);
429
            $rubrictemplate .= html_writer::tag('div', $input, array('class' => 'addcriterion btn btn-secondary'));
430
        }
431
        $rubrictemplate .= $this->rubric_edit_options($mode, $options);
432
        $rubrictemplate .= html_writer::end_tag('div');
433
 
434
        return str_replace('{NAME}', $elementname, $rubrictemplate);
435
    }
436
 
437
    /**
438
     * Generates html template to view/edit the rubric options. Expression {NAME} is used in
439
     * template for the form element name
440
     *
441
     * @param int $mode rubric display mode see {@link gradingform_rubric_controller}
442
     * @param array $options display options for this rubric, defaults are: {@link gradingform_rubric_controller::get_default_options()}
443
     * @return string
444
     */
445
    protected function rubric_edit_options($mode, $options) {
446
        if ($mode != gradingform_rubric_controller::DISPLAY_EDIT_FULL
447
                && $mode != gradingform_rubric_controller::DISPLAY_EDIT_FROZEN
448
                && $mode != gradingform_rubric_controller::DISPLAY_PREVIEW) {
449
            // Options are displayed only for people who can manage
450
            return;
451
        }
452
        $html = html_writer::start_tag('div', array('class' => 'options'));
453
        $html .= html_writer::tag('div', get_string('rubricoptions', 'gradingform_rubric'), array('class' => 'optionsheading'));
454
        $attrs = array('type' => 'hidden', 'name' => '{NAME}[options][optionsset]', 'value' => 1);
455
        foreach ($options as $option => $value) {
456
            $html .= html_writer::start_tag('div', array('class' => 'option '.$option));
457
            $attrs = array('name' => '{NAME}[options]['.$option.']', 'id' => '{NAME}-options-'.$option);
458
            switch ($option) {
459
                case 'sortlevelsasc':
460
                    // Display option as dropdown
461
                    $html .= html_writer::label(get_string($option, 'gradingform_rubric'), $attrs['id'], false);
462
                    $value = (int)(!!$value); // make sure $value is either 0 or 1
463
                    if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FULL) {
464
                        $selectoptions = array(0 => get_string($option.'0', 'gradingform_rubric'), 1 => get_string($option.'1', 'gradingform_rubric'));
465
                        $valuestr = html_writer::select($selectoptions, $attrs['name'], $value, false, array('id' => $attrs['id']));
466
                        $html .= html_writer::tag('span', $valuestr, array('class' => 'value'));
467
                    } else {
468
                        $html .= html_writer::tag('span', get_string($option.$value, 'gradingform_rubric'), array('class' => 'value'));
469
                        if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FROZEN) {
470
                            $html .= html_writer::empty_tag('input', $attrs + array('type' => 'hidden', 'value' => $value));
471
                        }
472
                    }
473
                    break;
474
                default:
475
                    if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FROZEN && $value) {
476
                        // Id should be different then the actual input added later.
477
                        $attrs['id'] .= '_hidden';
478
                        $html .= html_writer::empty_tag('input', $attrs + array('type' => 'hidden', 'value' => $value));
479
                    }
480
                    // Display option as checkbox
481
                    $attrs['type'] = 'checkbox';
482
                    $attrs['value'] = 1;
483
                    if ($value) {
484
                        $attrs['checked'] = 'checked';
485
                    }
486
                    if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FROZEN || $mode == gradingform_rubric_controller::DISPLAY_PREVIEW) {
487
                        $attrs['disabled'] = 'disabled';
488
                        unset($attrs['name']);
489
                        // Id should be different then the actual input added later.
490
                        $attrs['id'] .= '_disabled';
491
                    }
492
                    $html .= html_writer::empty_tag('input', $attrs);
493
                    $html .= html_writer::tag('label', get_string($option, 'gradingform_rubric'), array('for' => $attrs['id']));
494
                    break;
495
            }
496
            if (get_string_manager()->string_exists($option.'_help', 'gradingform_rubric')) {
497
                $html .= $this->help_icon($option, 'gradingform_rubric');
498
            }
499
            $html .= html_writer::end_tag('div'); // .option
500
        }
501
        $html .= html_writer::end_tag('div'); // .options
502
        return $html;
503
    }
504
 
505
    /**
506
     * This function returns html code for displaying rubric. Depending on $mode it may be the code
507
     * to edit rubric, to preview the rubric, to evaluate somebody or to review the evaluation.
508
     *
509
     * It is very unlikely that this function needs to be overriden by theme. It does not produce
510
     * any html code, it just prepares data about rubric design and evaluation, adds the CSS
511
     * class to elements and calls the functions level_template, criterion_template and
512
     * rubric_template
513
     *
514
     * @param array $criteria data about the rubric design
515
     * @param array $options display options for this rubric, defaults are: {@link gradingform_rubric_controller::get_default_options()}
516
     * @param int $mode rubric display mode, see {@link gradingform_rubric_controller}
517
     * @param string $elementname the name of the form element (in editor mode) or the prefix for div ids (in view mode)
518
     * @param array $values evaluation result
519
     * @return string
520
     */
521
    public function display_rubric($criteria, $options, $mode, $elementname = null, $values = null) {
522
        $criteriastr = '';
523
        $cnt = 0;
524
        foreach ($criteria as $id => $criterion) {
525
            $criterion['class'] = $this->get_css_class_suffix($cnt++, sizeof($criteria) -1);
526
            $criterion['id'] = $id;
527
            $levelsstr = '';
528
            $levelcnt = 0;
529
            if (isset($values['criteria'][$id])) {
530
                $criterionvalue = $values['criteria'][$id];
531
            } else {
532
                $criterionvalue = null;
533
            }
534
            $index = 1;
535
            foreach ($criterion['levels'] as $levelid => $level) {
536
                $level['id'] = $levelid;
537
                $level['class'] = $this->get_css_class_suffix($levelcnt++, sizeof($criterion['levels']) -1);
538
                $level['checked'] = (isset($criterionvalue['levelid']) && ((int)$criterionvalue['levelid'] === $levelid));
539
                if ($level['checked'] && ($mode == gradingform_rubric_controller::DISPLAY_EVAL_FROZEN || $mode == gradingform_rubric_controller::DISPLAY_REVIEW || $mode == gradingform_rubric_controller::DISPLAY_VIEW)) {
540
                    $level['class'] .= ' checked';
541
                    //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
542
                }
543
                if (isset($criterionvalue['savedlevelid']) && ((int)$criterionvalue['savedlevelid'] === $levelid)) {
544
                    $level['class'] .= ' currentchecked';
545
                }
546
                $level['tdwidth'] = 100/count($criterion['levels']);
547
                $level['index'] = $index;
548
                $levelsstr .= $this->level_template($mode, $options, $elementname, $id, $level);
549
                $index++;
550
            }
551
            $criteriastr .= $this->criterion_template($mode, $options, $elementname, $criterion, $levelsstr, $criterionvalue);
552
        }
553
        return $this->rubric_template($mode, $options, $elementname, $criteriastr);
554
    }
555
 
556
    /**
557
     * Help function to return CSS class names for element (first/last/even/odd) with leading space
558
     *
559
     * @param int $idx index of this element in the row/column
560
     * @param int $maxidx maximum index of the element in the row/column
561
     * @return string
562
     */
563
    protected function get_css_class_suffix($idx, $maxidx) {
564
        $class = '';
565
        if ($idx == 0) {
566
            $class .= ' first';
567
        }
568
        if ($idx == $maxidx) {
569
            $class .= ' last';
570
        }
571
        if ($idx%2) {
572
            $class .= ' odd';
573
        } else {
574
            $class .= ' even';
575
        }
576
        return $class;
577
    }
578
 
579
    /**
580
     * Displays for the student the list of instances or default content if no instances found
581
     *
582
     * @param array $instances array of objects of type gradingform_rubric_instance
583
     * @param string $defaultcontent default string that would be displayed without advanced grading
584
     * @param boolean $cangrade whether current user has capability to grade in this context
585
     * @return string
586
     */
587
    public function display_instances($instances, $defaultcontent, $cangrade) {
588
        $return = '';
589
        if (sizeof($instances)) {
590
            $return .= html_writer::start_tag('div', array('class' => 'advancedgrade'));
591
            $idx = 0;
592
            foreach ($instances as $instance) {
593
                $return .= $this->display_instance($instance, $idx++, $cangrade);
594
            }
595
            $return .= html_writer::end_tag('div');
596
        }
597
        return $return. $defaultcontent;
598
    }
599
 
600
    /**
601
     * Displays one grading instance
602
     *
603
     * @param gradingform_rubric_instance $instance
604
     * @param int $idx unique number of instance on page
605
     * @param bool $cangrade whether current user has capability to grade in this context
606
     */
607
    public function display_instance(gradingform_rubric_instance $instance, $idx, $cangrade) {
608
        $criteria = $instance->get_controller()->get_definition()->rubric_criteria;
609
        $options = $instance->get_controller()->get_options();
610
        $values = $instance->get_rubric_filling();
611
        if ($cangrade) {
612
            $mode = gradingform_rubric_controller::DISPLAY_REVIEW;
613
            $showdescription = $options['showdescriptionteacher'];
614
        } else {
615
            $mode = gradingform_rubric_controller::DISPLAY_VIEW;
616
            $showdescription = $options['showdescriptionstudent'];
617
        }
618
        $output = '';
619
        if ($showdescription) {
620
            $output .= $this->box($instance->get_controller()->get_formatted_description(), 'gradingform_rubric-description');
621
        }
622
        $output .= $this->display_rubric($criteria, $options, $mode, 'rubric'.$idx, $values);
623
        return $output;
624
    }
625
 
626
    /**
627
     * Displays confirmation that students require re-grading
628
     *
629
     * @param string $elementname
630
     * @param int $changelevel
631
     * @param string $value
632
     * @return string
633
     */
634
    public function display_regrade_confirmation($elementname, $changelevel, $value) {
635
        $html = html_writer::start_tag('div', array('class' => 'gradingform_rubric-regrade', 'role' => 'alert'));
636
        if ($changelevel<=2) {
637
            $html .= html_writer::label(get_string('regrademessage1', 'gradingform_rubric'), 'menu' . $elementname . 'regrade');
638
            $selectoptions = array(
639
 
640
                1 => get_string('regradeoption1', 'gradingform_rubric')
641
            );
642
            $html .= html_writer::select($selectoptions, $elementname.'[regrade]', $value, false);
643
        } else {
644
            $html .= get_string('regrademessage5', 'gradingform_rubric');
645
            $html .= html_writer::empty_tag('input', array('name' => $elementname.'[regrade]', 'value' => 1, 'type' => 'hidden'));
646
        }
647
        $html .= html_writer::end_tag('div');
648
        return $html;
649
    }
650
 
651
    /**
652
     * Generates and returns HTML code to display information box about how rubric score is converted to the grade
653
     *
654
     * @param array $scores
655
     * @return string
656
     */
657
    public function display_rubric_mapping_explained($scores) {
658
        $html = '';
659
        if (!$scores) {
660
            return $html;
661
        }
662
        if ($scores['minscore'] <> 0) {
663
            $html .= $this->output->notification(get_string('zerolevelsabsent', 'gradingform_rubric'), 'error');
664
        }
665
        $html .= $this->output->notification(get_string('rubricmappingexplained', 'gradingform_rubric', (object)$scores), 'info');
666
        return $html;
667
    }
668
}