See Release Notes
Long Term Support Release
Differences Between: [Versions 401 and 402] [Versions 401 and 403]
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 the Guide grading form renderer in all of its glory 19 * 20 * @package gradingform_guide 21 * @copyright 2012 Dan Marsden <dan@danmarsden.com> 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_guide 31 * @copyright 2012 Dan Marsden <dan@danmarsden.com> 32 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 33 */ 34 class gradingform_guide_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 guide, to preview the guide, to evaluate somebody or to review the evaluation. 39 * 40 * This function may be called from display_guide() to display the whole guide, or it can be 41 * called by itself to return a template used by JavaScript to add new empty criteria to the 42 * guide 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 guide display mode, one of gradingform_guide_controller::DISPLAY_* {@link gradingform_guide_controller()} 52 * @param array $options An array of options. 53 * showmarkspercriterionstudents (bool) If true adds the current score to the display 54 * @param string $elementname the name of the form element (in editor mode) or the prefix for div ids (in view mode) 55 * @param array $criterion criterion data 56 * @param array $value (only in view mode) teacher's feedback on this criterion 57 * @param array $validationerrors An array containing validation errors to be shown 58 * @param array $comments Array of frequently used comments. 59 * @return string 60 */ 61 public function criterion_template($mode, $options, $elementname = '{NAME}', $criterion = null, $value = null, 62 $validationerrors = null, $comments = null) { 63 64 if ($criterion === null || !is_array($criterion) || !array_key_exists('id', $criterion)) { 65 $criterion = array('id' => '{CRITERION-id}', 66 'description' => '{CRITERION-description}', 67 'sortorder' => '{CRITERION-sortorder}', 68 'class' => '{CRITERION-class}', 69 'descriptionmarkers' => '{CRITERION-descriptionmarkers}', 70 'shortname' => '{CRITERION-shortname}', 71 'maxscore' => '{CRITERION-maxscore}'); 72 } else { 73 foreach (array('sortorder', 'description', 'class', 'shortname', 'descriptionmarkers', 'maxscore') as $key) { 74 // Set missing array elements to empty strings to avoid warnings. 75 if (!array_key_exists($key, $criterion)) { 76 $criterion[$key] = ''; 77 } 78 } 79 } 80 81 $criteriontemplate = html_writer::start_tag('tr', array('class' => 'criterion'. $criterion['class'], 82 'id' => '{NAME}-criteria-{CRITERION-id}')); 83 $descriptionclass = 'description'; 84 if ($mode == gradingform_guide_controller::DISPLAY_EDIT_FULL) { 85 $criteriontemplate .= html_writer::start_tag('td', array('class' => 'controls')); 86 foreach (array('moveup', 'delete', 'movedown') as $key) { 87 $value = get_string('criterion'.$key, 'gradingform_guide'); 88 $button = html_writer::empty_tag('input', array('type' => 'submit', 89 'name' => '{NAME}[criteria][{CRITERION-id}]['.$key.']', 90 'id' => '{NAME}-criteria-{CRITERION-id}-'.$key, 'value' => $value, 'title' => $value)); 91 $criteriontemplate .= html_writer::tag('div', $button, array('class' => $key)); 92 } 93 $criteriontemplate .= html_writer::end_tag('td'); // Controls. 94 $criteriontemplate .= html_writer::empty_tag('input', array('type' => 'hidden', 95 'name' => '{NAME}[criteria][{CRITERION-id}][sortorder]', 'value' => $criterion['sortorder'])); 96 97 $shortnameinput = html_writer::empty_tag('input', array('type' => 'text', 98 'name' => '{NAME}[criteria][{CRITERION-id}][shortname]', 99 'id ' => '{NAME}-criteria-{CRITERION-id}-shortname', 100 'value' => $criterion['shortname'], 101 'aria-labelledby' => '{NAME}-criterion-name-label')); 102 $shortname = html_writer::tag('div', $shortnameinput, array('class' => 'criterionname')); 103 $descriptioninput = html_writer::tag('textarea', s($criterion['description']), 104 array('name' => '{NAME}[criteria][{CRITERION-id}][description]', 105 'id' => '{NAME}[criteria][{CRITERION-id}][description]', 'cols' => '65', 'rows' => '5')); 106 $description = html_writer::tag('div', $descriptioninput, array('class' => 'criteriondesc')); 107 108 $descriptionmarkersinput = html_writer::tag('textarea', s($criterion['descriptionmarkers']), 109 array('name' => '{NAME}[criteria][{CRITERION-id}][descriptionmarkers]', 110 'id' => '{NAME}[criteria][{CRITERION-id}][descriptionmarkers]', 'cols' => '65', 'rows' => '5')); 111 $descriptionmarkers = html_writer::tag('div', $descriptionmarkersinput, array('class' => 'criteriondescmarkers')); 112 113 $maxscore = html_writer::empty_tag('input', array('type'=> 'text', 114 'name' => '{NAME}[criteria][{CRITERION-id}][maxscore]', 'size' => '3', 115 'value' => $criterion['maxscore'], 116 'id' => '{NAME}[criteria][{CRITERION-id}][maxscore]')); 117 $maxscore = html_writer::tag('div', $maxscore, array('class'=>'criterionmaxscore')); 118 } else { 119 if ($mode == gradingform_guide_controller::DISPLAY_EDIT_FROZEN) { 120 $criteriontemplate .= html_writer::empty_tag('input', array('type' => 'hidden', 121 'name' => '{NAME}[criteria][{CRITERION-id}][sortorder]', 'value' => $criterion['sortorder'])); 122 $criteriontemplate .= html_writer::empty_tag('input', array('type' => 'hidden', 123 'name' => '{NAME}[criteria][{CRITERION-id}][shortname]', 'value' => $criterion['shortname'])); 124 $criteriontemplate .= html_writer::empty_tag('input', array('type' => 'hidden', 125 'name' => '{NAME}[criteria][{CRITERION-id}][description]', 'value' => $criterion['description'])); 126 $criteriontemplate .= html_writer::empty_tag('input', array('type' => 'hidden', 127 'name' => '{NAME}[criteria][{CRITERION-id}][descriptionmarkers]', 'value' => $criterion['descriptionmarkers'])); 128 $criteriontemplate .= html_writer::empty_tag('input', array('type' => 'hidden', 129 'name' => '{NAME}[criteria][{CRITERION-id}][maxscore]', 'value' => $criterion['maxscore'])); 130 } else if ($mode == gradingform_guide_controller::DISPLAY_EVAL || 131 $mode == gradingform_guide_controller::DISPLAY_VIEW) { 132 $descriptionclass = 'descriptionreadonly'; 133 } 134 135 $shortnameparams = array( 136 'name' => '{NAME}[criteria][{CRITERION-id}][shortname]', 137 'id' => '{NAME}[criteria][{CRITERION-id}][shortname]', 138 'aria-describedby' => '{NAME}-criterion-name-label' 139 ); 140 $shortname = html_writer::div(s($criterion['shortname']), 'criterionshortname', $shortnameparams); 141 142 $descmarkerclass = ''; 143 $descstudentclass = ''; 144 if ($mode == gradingform_guide_controller::DISPLAY_EVAL) { 145 if (!get_user_preferences('gradingform_guide-showmarkerdesc', true)) { 146 $descmarkerclass = ' hide'; 147 } 148 if (!get_user_preferences('gradingform_guide-showstudentdesc', true)) { 149 $descstudentclass = ' hide'; 150 } 151 } 152 $description = html_writer::tag('div', s($criterion['description']), 153 array('class'=>'criteriondescription'.$descstudentclass, 154 'name' => '{NAME}[criteria][{CRITERION-id}][descriptionmarkers]')); 155 $descriptionmarkers = html_writer::tag('div', s($criterion['descriptionmarkers']), 156 array('class'=>'criteriondescriptionmarkers'.$descmarkerclass, 157 'name' => '{NAME}[criteria][{CRITERION-id}][descriptionmarkers]')); 158 $maxscore = html_writer::tag('div', s($criterion['maxscore']), 159 array('class'=>'criteriondescriptionscore', 'name' => '{NAME}[criteria][{CRITERION-id}][maxscore]')); 160 161 // Retain newlines as <br> tags when displaying the marking guide. 162 $description = nl2br($description); 163 $descriptionmarkers = nl2br($descriptionmarkers); 164 } 165 166 if (isset($criterion['error_description'])) { 167 $descriptionclass .= ' error'; 168 } 169 170 $title = $shortname; 171 if ($mode == gradingform_guide_controller::DISPLAY_EDIT_FULL || 172 $mode == gradingform_guide_controller::DISPLAY_PREVIEW) { 173 $title .= html_writer::tag('label', get_string('descriptionstudents', 'gradingform_guide'), 174 array('for'=>'{NAME}[criteria][{CRITERION-id}][description]')); 175 $title .= $description; 176 $title .= html_writer::tag('label', get_string('descriptionmarkers', 'gradingform_guide'), 177 array('for'=>'{NAME}[criteria][{CRITERION-id}][descriptionmarkers]')); 178 $title .= $descriptionmarkers; 179 $title .= html_writer::tag('label', get_string('maxscore', 'gradingform_guide'), 180 array('for'=>'{NAME}[criteria][{CRITERION-id}][maxscore]')); 181 $title .= $maxscore; 182 } else if ($mode == gradingform_guide_controller::DISPLAY_PREVIEW_GRADED || 183 $mode == gradingform_guide_controller::DISPLAY_VIEW) { 184 $title .= $description; 185 if (!empty($options['showmarkspercriterionstudents'])) { 186 $title .= html_writer::label(get_string('maxscore', 'gradingform_guide'), null); 187 $title .= $maxscore; 188 } 189 } else { 190 $title .= $description . $descriptionmarkers; 191 } 192 193 // Title cell params. 194 $titletdparams = array( 195 'class' => $descriptionclass, 196 'id' => '{NAME}-criteria-{CRITERION-id}-shortname-cell' 197 ); 198 199 if ($mode != gradingform_guide_controller::DISPLAY_EDIT_FULL && 200 $mode != gradingform_guide_controller::DISPLAY_EDIT_FROZEN) { 201 // Set description's cell as tab-focusable. 202 $titletdparams['tabindex'] = '0'; 203 } 204 205 $criteriontemplate .= html_writer::tag('td', $title, $titletdparams); 206 207 $currentremark = ''; 208 $currentscore = ''; 209 if (isset($value['remark'])) { 210 $currentremark = $value['remark']; 211 } 212 if (isset($value['score'])) { 213 $currentscore = $value['score']; 214 } 215 216 // Element ID of the remark text area. 217 $remarkid = $elementname . '-criteria-' . $criterion['id'] . '-remark'; 218 219 if ($mode == gradingform_guide_controller::DISPLAY_EVAL) { 220 $scoreclass = ''; 221 if (!empty($validationerrors[$criterion['id']]['score'])) { 222 $scoreclass = 'error'; 223 $currentscore = $validationerrors[$criterion['id']]['score']; // Show invalid score in form. 224 } 225 226 // Grading remark text area parameters. 227 $remarkparams = array( 228 'name' => '{NAME}[criteria][{CRITERION-id}][remark]', 229 'id' => $remarkid, 230 'cols' => '65', 'rows' => '5', 'class' => 'markingguideremark form-control', 231 'aria-labelledby' => '{NAME}-remarklabel{CRITERION-id}' 232 ); 233 234 // Grading remark text area. 235 $input = html_writer::tag('textarea', s($currentremark), $remarkparams); 236 237 // Show the frequently-used comments chooser only if there are defined entries. 238 $commentchooser = ''; 239 if (!empty($comments)) { 240 // Frequently used comments chooser. 241 $chooserbuttonid = 'criteria-' . $criterion['id'] . '-commentchooser'; 242 $commentchooserparams = array('id' => $chooserbuttonid, 'class' => 'commentchooser btn btn-secondary'); 243 $commentchooser = html_writer::tag('button', get_string('insertcomment', 'gradingform_guide'), 244 $commentchooserparams); 245 246 // Option items for the frequently used comments chooser dialog. 247 $commentoptions = array(); 248 foreach ($comments as $id => $comment) { 249 $commentoption = new stdClass(); 250 $commentoption->id = $id; 251 $commentoption->description = $comment['description']; 252 $commentoptions[] = $commentoption; 253 } 254 255 // Include string for JS for the comment chooser title. 256 $this->page->requires->string_for_js('insertcomment', 'gradingform_guide'); 257 // Include comment_chooser module. 258 $this->page->requires->js_call_amd('gradingform_guide/comment_chooser', 'initialise', 259 array($criterion['id'], $chooserbuttonid, $remarkid, $commentoptions)); 260 } 261 262 // Hidden marking guide remark label. 263 $remarklabelparams = array( 264 'class' => 'hidden', 265 'id' => '{NAME}-remarklabel{CRITERION-id}' 266 ); 267 $remarklabeltext = get_string('criterionremark', 'gradingform_guide', $criterion['shortname']); 268 $remarklabel = html_writer::label($remarklabeltext, $remarkid, false, $remarklabelparams); 269 270 $criteriontemplate .= html_writer::tag('td', $remarklabel . $input . $commentchooser, array('class' => 'remark')); 271 272 // Score input and max score. 273 $scoreinputparams = array( 274 'type' => 'text', 275 'name' => '{NAME}[criteria][{CRITERION-id}][score]', 276 'class' => $scoreclass . ' form-control', 277 'id' => '{NAME}-criteria-{CRITERION-id}-score', 278 'size' => '3', 279 'value' => $currentscore, 280 'aria-labelledby' => '{NAME}-score-label' 281 ); 282 $score = html_writer::empty_tag('input', $scoreinputparams); 283 $score .= html_writer::div('/' . s($criterion['maxscore'])); 284 285 $criteriontemplate .= html_writer::tag('td', $score, array('class' => 'score')); 286 } else if ($mode == gradingform_guide_controller::DISPLAY_EVAL_FROZEN) { 287 $criteriontemplate .= html_writer::empty_tag('input', array('type' => 'hidden', 288 'name' => '{NAME}[criteria][{CRITERION-id}][remark]', 'value' => $currentremark)); 289 } else if ($mode == gradingform_guide_controller::DISPLAY_REVIEW || 290 $mode == gradingform_guide_controller::DISPLAY_VIEW) { 291 292 // Hidden marking guide remark description. 293 $remarkdescparams = array( 294 'id' => '{NAME}-criteria-{CRITERION-id}-remark-desc' 295 ); 296 $remarkdesctext = get_string('criterionremark', 'gradingform_guide', $criterion['shortname']); 297 $remarkdesc = html_writer::div($remarkdesctext, 'hidden', $remarkdescparams); 298 299 // Remarks cell. 300 $remarkdiv = html_writer::div(s($currentremark)); 301 $remarkcellparams = array( 302 'class' => 'remark', 303 'tabindex' => '0', 304 'id' => '{NAME}-criteria-{CRITERION-id}-remark', 305 'aria-describedby' => '{NAME}-criteria-{CRITERION-id}-remark-desc' 306 ); 307 $criteriontemplate .= html_writer::tag('td', $remarkdesc . $remarkdiv, $remarkcellparams); 308 309 // Score cell. 310 if (!empty($options['showmarkspercriterionstudents'])) { 311 $scorecellparams = array( 312 'class' => 'score', 313 'tabindex' => '0', 314 'id' => '{NAME}-criteria-{CRITERION-id}-score', 315 'aria-describedby' => '{NAME}-score-label' 316 ); 317 $scorediv = html_writer::div(s($currentscore) . ' / ' . s($criterion['maxscore'])); 318 $criteriontemplate .= html_writer::tag('td', $scorediv, $scorecellparams); 319 } 320 } 321 $criteriontemplate .= html_writer::end_tag('tr'); // Criterion. 322 323 $criteriontemplate = str_replace('{NAME}', $elementname, $criteriontemplate); 324 $criteriontemplate = str_replace('{CRITERION-id}', $criterion['id'], $criteriontemplate); 325 return $criteriontemplate; 326 } 327 328 /** 329 * This function returns html code for displaying criterion. Depending on $mode it may be the 330 * code to edit guide, to preview the guide, to evaluate somebody or to review the evaluation. 331 * 332 * This function may be called from display_guide() to display the whole guide, or it can be 333 * called by itself to return a template used by JavaScript to add new empty criteria to the 334 * guide being designed. 335 * In this case it will use macros like {NAME}, {LEVELS}, {CRITERION-id}, etc. 336 * 337 * When overriding this function it is very important to remember that all elements of html 338 * form (in edit or evaluate mode) must have the name $elementname. 339 * 340 * Also JavaScript relies on the class names of elements and when developer changes them 341 * script might stop working. 342 * 343 * @param int $mode guide display mode, one of gradingform_guide_controller::DISPLAY_* {@link gradingform_guide_controller} 344 * @param string $elementname the name of the form element (in editor mode) or the prefix for div ids (in view mode) 345 * @param array $comment 346 * @return string 347 */ 348 public function comment_template($mode, $elementname = '{NAME}', $comment = null) { 349 if ($comment === null || !is_array($comment) || !array_key_exists('id', $comment)) { 350 $comment = array('id' => '{COMMENT-id}', 351 'description' => '{COMMENT-description}', 352 'sortorder' => '{COMMENT-sortorder}', 353 'class' => '{COMMENT-class}'); 354 } else { 355 foreach (array('sortorder', 'description', 'class') as $key) { 356 // Set missing array elements to empty strings to avoid warnings. 357 if (!array_key_exists($key, $comment)) { 358 $criterion[$key] = ''; 359 } 360 } 361 } 362 $commenttemplate = html_writer::start_tag('tr', array('class' => 'criterion'. $comment['class'], 363 'id' => '{NAME}-comments-{COMMENT-id}')); 364 if ($mode == gradingform_guide_controller::DISPLAY_EDIT_FULL) { 365 $commenttemplate .= html_writer::start_tag('td', array('class' => 'controls')); 366 foreach (array('moveup', 'delete', 'movedown') as $key) { 367 $value = get_string('comments'.$key, 'gradingform_guide'); 368 $button = html_writer::empty_tag('input', array('type' => 'submit', 369 'name' => '{NAME}[comments][{COMMENT-id}]['.$key.']', 'id' => '{NAME}-comments-{COMMENT-id}-'.$key, 370 'value' => $value, 'title' => $value)); 371 $commenttemplate .= html_writer::tag('div', $button, array('class' => $key)); 372 } 373 $commenttemplate .= html_writer::end_tag('td'); // Controls. 374 $commenttemplate .= html_writer::empty_tag('input', array('type' => 'hidden', 375 'name' => '{NAME}[comments][{COMMENT-id}][sortorder]', 'value' => $comment['sortorder'])); 376 $description = html_writer::tag('textarea', s($comment['description']), 377 array('name' => '{NAME}[comments][{COMMENT-id}][description]', 378 'id' => '{NAME}-comments-{COMMENT-id}-description', 379 'aria-labelledby' => '{NAME}-comment-label', 'cols' => '65', 'rows' => '5')); 380 $description = html_writer::tag('div', $description, array('class'=>'criteriondesc')); 381 } else { 382 if ($mode == gradingform_guide_controller::DISPLAY_EDIT_FROZEN) { 383 $commenttemplate .= html_writer::empty_tag('input', array('type' => 'hidden', 384 'name' => '{NAME}[comments][{COMMENT-id}][sortorder]', 'value' => $comment['sortorder'])); 385 $commenttemplate .= html_writer::empty_tag('input', array('type' => 'hidden', 386 'name' => '{NAME}[comments][{COMMENT-id}][description]', 'value' => $comment['description'])); 387 } 388 if ($mode == gradingform_guide_controller::DISPLAY_EVAL) { 389 $description = html_writer::tag('span', s($comment['description']), 390 array('name' => '{NAME}[comments][{COMMENT-id}][description]', 391 'title' => get_string('clicktocopy', 'gradingform_guide'), 392 'id' => '{NAME}[comments][{COMMENT-id}]', 'class'=>'markingguidecomment')); 393 } else { 394 $description = s($comment['description']); 395 } 396 // Retain newlines as <br> tags when displaying 'frequently used comments'. 397 $description = nl2br($description); 398 } 399 $descriptionclass = 'description'; 400 if (isset($comment['error_description'])) { 401 $descriptionclass .= ' error'; 402 } 403 $descriptioncellparams = array( 404 'class' => $descriptionclass, 405 'id' => '{NAME}-comments-{COMMENT-id}-description-cell' 406 ); 407 // Make description cell tab-focusable when in review mode. 408 if ($mode != gradingform_guide_controller::DISPLAY_EDIT_FULL && 409 $mode != gradingform_guide_controller::DISPLAY_EDIT_FROZEN) { 410 $descriptioncellparams['tabindex'] = '0'; 411 } 412 $commenttemplate .= html_writer::tag('td', $description, $descriptioncellparams); 413 $commenttemplate .= html_writer::end_tag('tr'); // Criterion. 414 415 $commenttemplate = str_replace('{NAME}', $elementname, $commenttemplate); 416 $commenttemplate = str_replace('{COMMENT-id}', $comment['id'], $commenttemplate); 417 return $commenttemplate; 418 } 419 /** 420 * This function returns html code for displaying guide template (content before and after 421 * criteria list). Depending on $mode it may be the code to edit guide, to preview the guide, 422 * to evaluate somebody or to review the evaluation. 423 * 424 * This function is called from display_guide() to display the whole guide. 425 * 426 * When overriding this function it is very important to remember that all elements of html 427 * form (in edit or evaluate mode) must have the name $elementname. 428 * 429 * Also JavaScript relies on the class names of elements and when developer changes them 430 * script might stop working. 431 * 432 * @param int $mode guide display mode, one of gradingform_guide_controller::DISPLAY_* {@link gradingform_guide_controller} 433 * @param array $options An array of options provided to {@link gradingform_guide_renderer::guide_edit_options()} 434 * @param string $elementname the name of the form element (in editor mode) or the prefix for div ids (in view mode) 435 * @param string $criteriastr evaluated templates for this guide's criteria 436 * @param string $commentstr 437 * @return string 438 */ 439 protected function guide_template($mode, $options, $elementname, $criteriastr, $commentstr) { 440 $classsuffix = ''; // CSS suffix for class of the main div. Depends on the mode. 441 switch ($mode) { 442 case gradingform_guide_controller::DISPLAY_EDIT_FULL: 443 $classsuffix = ' editor editable'; 444 break; 445 case gradingform_guide_controller::DISPLAY_EDIT_FROZEN: 446 $classsuffix = ' editor frozen'; 447 break; 448 case gradingform_guide_controller::DISPLAY_PREVIEW: 449 case gradingform_guide_controller::DISPLAY_PREVIEW_GRADED: 450 $classsuffix = ' editor preview'; 451 break; 452 case gradingform_guide_controller::DISPLAY_EVAL: 453 $classsuffix = ' evaluate editable'; 454 break; 455 case gradingform_guide_controller::DISPLAY_EVAL_FROZEN: 456 $classsuffix = ' evaluate frozen'; 457 break; 458 case gradingform_guide_controller::DISPLAY_REVIEW: 459 $classsuffix = ' review'; 460 break; 461 case gradingform_guide_controller::DISPLAY_VIEW: 462 $classsuffix = ' view'; 463 break; 464 } 465 466 $guidetemplate = html_writer::start_tag('div', array('id' => 'guide-{NAME}', 467 'class' => 'clearfix gradingform_guide'.$classsuffix)); 468 469 // Hidden guide label. 470 $guidedescparams = array( 471 'id' => 'guide-{NAME}-desc', 472 'aria-hidden' => 'true' 473 ); 474 $guidetemplate .= html_writer::div(get_string('guide', 'gradingform_guide'), 'hidden', $guidedescparams); 475 476 // Hidden criterion name label/description. 477 $guidetemplate .= html_writer::div(get_string('criterionname', 'gradingform_guide'), 'hidden', 478 array('id' => '{NAME}-criterion-name-label')); 479 480 // Hidden score label/description. 481 $guidetemplate .= html_writer::div(get_string('score', 'gradingform_guide'), 'hidden', array('id' => '{NAME}-score-label')); 482 483 // Criteria table parameters. 484 $criteriatableparams = array( 485 'class' => 'criteria', 486 'id' => '{NAME}-criteria', 487 'aria-describedby' => 'guide-{NAME}-desc'); 488 $guidetemplate .= html_writer::tag('table', $criteriastr, $criteriatableparams); 489 if ($mode == gradingform_guide_controller::DISPLAY_EDIT_FULL) { 490 $value = get_string('addcriterion', 'gradingform_guide'); 491 $input = html_writer::empty_tag('input', array('type' => 'submit', 'name' => '{NAME}[criteria][addcriterion]', 492 'id' => '{NAME}-criteria-addcriterion', 'value' => $value, 'title' => $value)); 493 $guidetemplate .= html_writer::tag('div', $input, array('class' => 'addcriterion')); 494 } 495 496 if (!empty($commentstr)) { 497 $guidetemplate .= html_writer::div(get_string('comments', 'gradingform_guide'), 'commentheader', 498 array('id' => '{NAME}-comments-label')); 499 $guidetemplate .= html_writer::div(get_string('comment', 'gradingform_guide'), 'hidden', 500 array('id' => '{NAME}-comment-label', 'aria-hidden' => 'true')); 501 $commentstableparams = array( 502 'class' => 'comments', 503 'id' => '{NAME}-comments', 504 'aria-describedby' => '{NAME}-comments-label'); 505 $guidetemplate .= html_writer::tag('table', $commentstr, $commentstableparams); 506 } 507 if ($mode == gradingform_guide_controller::DISPLAY_EDIT_FULL) { 508 $value = get_string('addcomment', 'gradingform_guide'); 509 $input = html_writer::empty_tag('input', array('type' => 'submit', 'name' => '{NAME}[comments][addcomment]', 510 'id' => '{NAME}-comments-addcomment', 'value' => $value, 'title' => $value)); 511 $guidetemplate .= html_writer::tag('div', $input, array('class' => 'addcomment')); 512 } 513 514 $guidetemplate .= $this->guide_edit_options($mode, $options); 515 $guidetemplate .= html_writer::end_tag('div'); 516 517 return str_replace('{NAME}', $elementname, $guidetemplate); 518 } 519 520 /** 521 * Generates html template to view/edit the guide options. Expression {NAME} is used in 522 * template for the form element name 523 * 524 * @param int $mode guide display mode, one of gradingform_guide_controller::DISPLAY_* {@link gradingform_guide_controller} 525 * @param array $options 526 * @return string 527 */ 528 protected function guide_edit_options($mode, $options) { 529 if ($mode != gradingform_guide_controller::DISPLAY_EDIT_FULL 530 && $mode != gradingform_guide_controller::DISPLAY_EDIT_FROZEN 531 && $mode != gradingform_guide_controller::DISPLAY_PREVIEW) { 532 // Options are displayed only for people who can manage. 533 return; 534 } 535 $html = html_writer::start_tag('div', array('class' => 'options')); 536 $html .= html_writer::tag('div', get_string('guideoptions', 'gradingform_guide'), array('class' => 'optionsheading')); 537 $attrs = array('type' => 'hidden', 'name' => '{NAME}[options][optionsset]', 'value' => 1, 'class' => 'form-control'); 538 $html .= html_writer::empty_tag('input', $attrs); 539 foreach ($options as $option => $value) { 540 $html .= html_writer::start_tag('div', array('class' => 'option '.$option)); 541 $attrs = array('name' => '{NAME}[options]['.$option.']', 'id' => '{NAME}-options-'.$option); 542 switch ($option) { 543 case 'sortlevelsasc': 544 // Display option as dropdown. 545 $html .= html_writer::tag('span', get_string($option, 'gradingform_guide'), array('class' => 'label')); 546 $value = (int)(!!$value); // Make sure $value is either 0 or 1. 547 if ($mode == gradingform_guide_controller::DISPLAY_EDIT_FULL) { 548 $selectoptions = array(0 => get_string($option.'0', 'gradingform_guide'), 549 1 => get_string($option.'1', 'gradingform_guide')); 550 $valuestr = html_writer::select($selectoptions, $attrs['name'], $value, false, array('id' => $attrs['id'])); 551 $html .= html_writer::tag('span', $valuestr, array('class' => 'value')); 552 // TODO add here button 'Sort levels'. 553 } else { 554 $html .= html_writer::tag('span', get_string($option.$value, 'gradingform_guide'), 555 array('class' => 'value')); 556 if ($mode == gradingform_guide_controller::DISPLAY_EDIT_FROZEN) { 557 $html .= html_writer::empty_tag('input', $attrs + array('type' => 'hidden', 'value' => $value)); 558 } 559 } 560 break; 561 default: 562 if ($mode == gradingform_guide_controller::DISPLAY_EDIT_FROZEN && $value) { 563 $html .= html_writer::empty_tag('input', $attrs + array('type' => 'hidden', 'value' => $value)); 564 } 565 // Display option as checkbox. 566 $attrs['type'] = 'checkbox'; 567 $attrs['value'] = 1; 568 if ($value) { 569 $attrs['checked'] = 'checked'; 570 } 571 if ($mode == gradingform_guide_controller::DISPLAY_EDIT_FROZEN || 572 $mode == gradingform_guide_controller::DISPLAY_PREVIEW) { 573 $attrs['disabled'] = 'disabled'; 574 unset($attrs['name']); 575 } 576 $html .= html_writer::empty_tag('input', $attrs); 577 $html .= html_writer::tag('label', get_string($option, 'gradingform_guide'), array('for' => $attrs['id'])); 578 break; 579 } 580 $html .= html_writer::end_tag('div'); // Option. 581 } 582 $html .= html_writer::end_tag('div'); // Options. 583 return $html; 584 } 585 586 /** 587 * This function returns html code for displaying guide. Depending on $mode it may be the code 588 * to edit guide, to preview the guide, to evaluate somebody or to review the evaluation. 589 * 590 * It is very unlikely that this function needs to be overriden by theme. It does not produce 591 * any html code, it just prepares data about guide design and evaluation, adds the CSS 592 * class to elements and calls the functions level_template, criterion_template and 593 * guide_template 594 * 595 * @param array $criteria data about the guide design 596 * @param array $comments 597 * @param array $options 598 * @param int $mode guide display mode, one of gradingform_guide_controller::DISPLAY_* {@link gradingform_guide_controller} 599 * @param string $elementname the name of the form element (in editor mode) or the prefix for div ids (in view mode) 600 * @param array $values evaluation result 601 * @param array $validationerrors 602 * @return string 603 */ 604 public function display_guide($criteria, $comments, $options, $mode, $elementname = null, $values = null, 605 $validationerrors = null) { 606 $criteriastr = ''; 607 $cnt = 0; 608 foreach ($criteria as $id => $criterion) { 609 $criterion['class'] = $this->get_css_class_suffix($cnt++, count($criteria) -1); 610 $criterion['id'] = $id; 611 if (isset($values['criteria'][$id])) { 612 $criterionvalue = $values['criteria'][$id]; 613 } else { 614 $criterionvalue = null; 615 } 616 $criteriastr .= $this->criterion_template($mode, $options, $elementname, $criterion, $criterionvalue, 617 $validationerrors, $comments); 618 } 619 620 $cnt = 0; 621 $commentstr = ''; 622 // Check if comments should be displayed. 623 if ($mode == gradingform_guide_controller::DISPLAY_EDIT_FULL || 624 $mode == gradingform_guide_controller::DISPLAY_EDIT_FROZEN || 625 $mode == gradingform_guide_controller::DISPLAY_PREVIEW || 626 $mode == gradingform_guide_controller::DISPLAY_EVAL_FROZEN) { 627 628 foreach ($comments as $id => $comment) { 629 $comment['id'] = $id; 630 $comment['class'] = $this->get_css_class_suffix($cnt++, count($comments) -1); 631 $commentstr .= $this->comment_template($mode, $elementname, $comment); 632 } 633 } 634 $output = $this->guide_template($mode, $options, $elementname, $criteriastr, $commentstr); 635 if ($mode == gradingform_guide_controller::DISPLAY_EVAL) { 636 $showdesc = get_user_preferences('gradingform_guide-showmarkerdesc', true); 637 $showdescstud = get_user_preferences('gradingform_guide-showstudentdesc', true); 638 $checked1 = array(); 639 $checked2 = array(); 640 $checked_s1 = array(); 641 $checked_s2 = array(); 642 $checked = array('checked' => 'checked'); 643 if ($showdesc) { 644 $checked1 = $checked; 645 } else { 646 $checked2 = $checked; 647 } 648 if ($showdescstud) { 649 $checked_s1 = $checked; 650 } else { 651 $checked_s2 = $checked; 652 } 653 654 $radio1 = html_writer::tag('input', get_string('showmarkerdesc', 'gradingform_guide'), array('type' => 'radio', 655 'name' => 'showmarkerdesc', 656 'value' => "true")+$checked1); 657 $radio1 = html_writer::tag('label', $radio1); 658 $radio2 = html_writer::tag('input', get_string('hidemarkerdesc', 'gradingform_guide'), array('type' => 'radio', 659 'name' => 'showmarkerdesc', 660 'value' => "false")+$checked2); 661 $radio2 = html_writer::tag('label', $radio2); 662 $output .= html_writer::tag('div', $radio1 . $radio2, array('class' => 'showmarkerdesc')); 663 664 $radio1 = html_writer::tag('input', get_string('showstudentdesc', 'gradingform_guide'), array('type' => 'radio', 665 'name' => 'showstudentdesc', 666 'value' => "true")+$checked_s1); 667 $radio1 = html_writer::tag('label', $radio1); 668 $radio2 = html_writer::tag('input', get_string('hidestudentdesc', 'gradingform_guide'), array('type' => 'radio', 669 'name' => 'showstudentdesc', 670 'value' => "false")+$checked_s2); 671 $radio2 = html_writer::tag('label', $radio2); 672 $output .= html_writer::tag('div', $radio1 . $radio2, array('class' => 'showstudentdesc')); 673 } 674 return $output; 675 } 676 677 /** 678 * Help function to return CSS class names for element (first/last/even/odd) with leading space 679 * 680 * @param int $idx index of this element in the row/column 681 * @param int $maxidx maximum index of the element in the row/column 682 * @return string 683 */ 684 protected function get_css_class_suffix($idx, $maxidx) { 685 $class = ''; 686 if ($idx == 0) { 687 $class .= ' first'; 688 } 689 if ($idx == $maxidx) { 690 $class .= ' last'; 691 } 692 if ($idx % 2) { 693 $class .= ' odd'; 694 } else { 695 $class .= ' even'; 696 } 697 return $class; 698 } 699 700 /** 701 * Displays for the student the list of instances or default content if no instances found 702 * 703 * @param array $instances array of objects of type gradingform_guide_instance 704 * @param string $defaultcontent default string that would be displayed without advanced grading 705 * @param bool $cangrade whether current user has capability to grade in this context 706 * @return string 707 */ 708 public function display_instances($instances, $defaultcontent, $cangrade) { 709 $return = ''; 710 if (count($instances)) { 711 $return .= html_writer::start_tag('div', array('class' => 'advancedgrade')); 712 $idx = 0; 713 foreach ($instances as $instance) { 714 $return .= $this->display_instance($instance, $idx++, $cangrade); 715 } 716 $return .= html_writer::end_tag('div'); 717 } 718 return $return. $defaultcontent; 719 } 720 721 /** 722 * Displays one grading instance 723 * 724 * @param gradingform_guide_instance $instance 725 * @param int $idx unique number of instance on page 726 * @param bool $cangrade whether current user has capability to grade in this context 727 */ 728 public function display_instance(gradingform_guide_instance $instance, $idx, $cangrade) { 729 $criteria = $instance->get_controller()->get_definition()->guide_criteria; 730 $options = $instance->get_controller()->get_options(); 731 $values = $instance->get_guide_filling(); 732 if ($cangrade) { 733 $mode = gradingform_guide_controller::DISPLAY_REVIEW; 734 } else { 735 $mode = gradingform_guide_controller::DISPLAY_VIEW; 736 } 737 738 $output = $this->box($instance->get_controller()->get_formatted_description(), 'gradingform_guide-description'). 739 $this->display_guide($criteria, array(), $options, $mode, 'guide'.$idx, $values); 740 return $output; 741 } 742 743 744 /** 745 * Displays a confirmation message after a regrade has occured 746 * 747 * @param string $elementname 748 * @param int $changelevel 749 * @param int $value The regrade option that was used 750 * @return string 751 */ 752 public function display_regrade_confirmation($elementname, $changelevel, $value) { 753 $html = html_writer::start_tag('div', array('class' => 'gradingform_guide-regrade', 'role' => 'alert')); 754 if ($changelevel<=2) { 755 $html .= get_string('regrademessage1', 'gradingform_guide'); 756 $selectoptions = array( 757 0 => get_string('regradeoption0', 'gradingform_guide'), 758 1 => get_string('regradeoption1', 'gradingform_guide') 759 ); 760 $html .= html_writer::select($selectoptions, $elementname.'[regrade]', $value, false); 761 } else { 762 $html .= get_string('regrademessage5', 'gradingform_guide'); 763 $html .= html_writer::empty_tag('input', array('name' => $elementname.'[regrade]', 'value' => 1, 'type' => 'hidden')); 764 } 765 $html .= html_writer::end_tag('div'); 766 return $html; 767 } 768 /** 769 * Generates and returns HTML code to display information box about how guide score is converted to the grade 770 * 771 * @param array $scores 772 * @return string 773 */ 774 public function display_guide_mapping_explained($scores) { 775 $html = ''; 776 if (!$scores) { 777 return $html; 778 } 779 if (isset($scores['modulegrade']) && $scores['maxscore'] != $scores['modulegrade']) { 780 $html .= $this->box(html_writer::tag('div', get_string('guidemappingexplained', 'gradingform_guide', (object)$scores)) 781 , 'generalbox gradingform_guide-error'); 782 } 783 784 return $html; 785 } 786 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body