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