Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.

/**
 * Contains the Guide grading form renderer in all of its glory
 *
 * @package    gradingform_guide
 * @copyright  2012 Dan Marsden <dan@danmarsden.com>
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */

defined('MOODLE_INTERNAL') || die();

/**
 * Grading method plugin renderer
 *
 * @package    gradingform_guide
 * @copyright  2012 Dan Marsden <dan@danmarsden.com>
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */
class gradingform_guide_renderer extends plugin_renderer_base {

    /**
     * This function returns html code for displaying criterion. Depending on $mode it may be the
     * code to edit guide, to preview the guide, to evaluate somebody or to review the evaluation.
     *
     * This function may be called from display_guide() to display the whole guide, or it can be
     * called by itself to return a template used by JavaScript to add new empty criteria to the
     * guide being designed.
     * In this case it will use macros like {NAME}, {LEVELS}, {CRITERION-id}, etc.
     *
     * When overriding this function it is very important to remember that all elements of html
     * form (in edit or evaluate mode) must have the name $elementname.
     *
     * Also JavaScript relies on the class names of elements and when developer changes them
     * script might stop working.
     *
     * @param int $mode guide display mode, one of gradingform_guide_controller::DISPLAY_* {@link gradingform_guide_controller()}
     * @param array $options An array of options.
     *      showmarkspercriterionstudents (bool) If true adds the current score to the display
     * @param string $elementname the name of the form element (in editor mode) or the prefix for div ids (in view mode)
     * @param array $criterion criterion data
     * @param array $value (only in view mode) teacher's feedback on this criterion
     * @param array $validationerrors An array containing validation errors to be shown
     * @param array $comments Array of frequently used comments.
     * @return string
     */
    public function criterion_template($mode, $options, $elementname = '{NAME}', $criterion = null, $value = null,
                                       $validationerrors = null, $comments = null) {

        if ($criterion === null || !is_array($criterion) || !array_key_exists('id', $criterion)) {
            $criterion = array('id' => '{CRITERION-id}',
                               'description' => '{CRITERION-description}',
                               'sortorder' => '{CRITERION-sortorder}',
                               'class' => '{CRITERION-class}',
                               'descriptionmarkers' => '{CRITERION-descriptionmarkers}',
                               'shortname' => '{CRITERION-shortname}',
                               'maxscore' => '{CRITERION-maxscore}');
        } else {
            foreach (array('sortorder', 'description', 'class', 'shortname', 'descriptionmarkers', 'maxscore') as $key) {
                // Set missing array elements to empty strings to avoid warnings.
                if (!array_key_exists($key, $criterion)) {
                    $criterion[$key] = '';
                }
            }
        }

        $criteriontemplate = html_writer::start_tag('tr', array('class' => 'criterion'. $criterion['class'],
            'id' => '{NAME}-criteria-{CRITERION-id}'));
        $descriptionclass = 'description';
        if ($mode == gradingform_guide_controller::DISPLAY_EDIT_FULL) {
            $criteriontemplate .= html_writer::start_tag('td', array('class' => 'controls'));
            foreach (array('moveup', 'delete', 'movedown') as $key) {
                $value = get_string('criterion'.$key, 'gradingform_guide');
                $button = html_writer::empty_tag('input', array('type' => 'submit',
                    'name' => '{NAME}[criteria][{CRITERION-id}]['.$key.']',
                    'id' => '{NAME}-criteria-{CRITERION-id}-'.$key, 'value' => $value, 'title' => $value));
                $criteriontemplate .= html_writer::tag('div', $button, array('class' => $key));
            }
            $criteriontemplate .= html_writer::end_tag('td'); // Controls.
            $criteriontemplate .= html_writer::empty_tag('input', array('type' => 'hidden',
                'name' => '{NAME}[criteria][{CRITERION-id}][sortorder]', 'value' => $criterion['sortorder']));

            $shortnameinput = html_writer::empty_tag('input', array('type' => 'text',
                'name' => '{NAME}[criteria][{CRITERION-id}][shortname]',
                'id ' => '{NAME}-criteria-{CRITERION-id}-shortname',
                'value' => $criterion['shortname'],
                'aria-labelledby' => '{NAME}-criterion-name-label'));
            $shortname = html_writer::tag('div', $shortnameinput, array('class' => 'criterionname'));
            $descriptioninput = html_writer::tag('textarea', s($criterion['description']),
                array('name' => '{NAME}[criteria][{CRITERION-id}][description]',
                      'id' => '{NAME}[criteria][{CRITERION-id}][description]', 'cols' => '65', 'rows' => '5'));
            $description = html_writer::tag('div', $descriptioninput, array('class' => 'criteriondesc'));

            $descriptionmarkersinput = html_writer::tag('textarea', s($criterion['descriptionmarkers']),
                array('name' => '{NAME}[criteria][{CRITERION-id}][descriptionmarkers]',
                      'id' => '{NAME}[criteria][{CRITERION-id}][descriptionmarkers]', 'cols' => '65', 'rows' => '5'));
            $descriptionmarkers = html_writer::tag('div', $descriptionmarkersinput, array('class' => 'criteriondescmarkers'));

            $maxscore = html_writer::empty_tag('input', array('type'=> 'text',
                'name' => '{NAME}[criteria][{CRITERION-id}][maxscore]', 'size' => '3',
                'value' => $criterion['maxscore'],
                'id' => '{NAME}[criteria][{CRITERION-id}][maxscore]'));
            $maxscore = html_writer::tag('div', $maxscore, array('class'=>'criterionmaxscore'));
        } else {
            if ($mode == gradingform_guide_controller::DISPLAY_EDIT_FROZEN) {
                $criteriontemplate .= html_writer::empty_tag('input', array('type' => 'hidden',
                    'name' => '{NAME}[criteria][{CRITERION-id}][sortorder]', 'value' => $criterion['sortorder']));
                $criteriontemplate .= html_writer::empty_tag('input', array('type' => 'hidden',
                    'name' => '{NAME}[criteria][{CRITERION-id}][shortname]', 'value' => $criterion['shortname']));
                $criteriontemplate .= html_writer::empty_tag('input', array('type' => 'hidden',
                    'name' => '{NAME}[criteria][{CRITERION-id}][description]', 'value' => $criterion['description']));
                $criteriontemplate .= html_writer::empty_tag('input', array('type' => 'hidden',
                    'name' => '{NAME}[criteria][{CRITERION-id}][descriptionmarkers]', 'value' => $criterion['descriptionmarkers']));
                $criteriontemplate .= html_writer::empty_tag('input', array('type' => 'hidden',
                    'name' => '{NAME}[criteria][{CRITERION-id}][maxscore]', 'value' => $criterion['maxscore']));
            } else if ($mode == gradingform_guide_controller::DISPLAY_EVAL ||
                       $mode == gradingform_guide_controller::DISPLAY_VIEW) {
                $descriptionclass = 'descriptionreadonly';
            }

            $shortnameparams = array(
                'name' => '{NAME}[criteria][{CRITERION-id}][shortname]',
                'id' => '{NAME}[criteria][{CRITERION-id}][shortname]',
                'aria-describedby' => '{NAME}-criterion-name-label'
            );
< $shortname = html_writer::div(s($criterion['shortname']), 'criterionshortname', $shortnameparams);
> $shortname = html_writer::div( > format_text($criterion['shortname'], FORMAT_HTML), > 'criterionshortname', > $shortnameparams > );
$descmarkerclass = ''; $descstudentclass = ''; if ($mode == gradingform_guide_controller::DISPLAY_EVAL) { if (!get_user_preferences('gradingform_guide-showmarkerdesc', true)) { $descmarkerclass = ' hide'; } if (!get_user_preferences('gradingform_guide-showstudentdesc', true)) { $descstudentclass = ' hide'; } }
< $description = html_writer::tag('div', s($criterion['description']),
> $description = html_writer::tag('div', > format_text($criterion['description'], $criterion['descriptionformat']),
array('class'=>'criteriondescription'.$descstudentclass, 'name' => '{NAME}[criteria][{CRITERION-id}][descriptionmarkers]'));
< $descriptionmarkers = html_writer::tag('div', s($criterion['descriptionmarkers']),
> $descriptionmarkers = html_writer::tag('div', > format_text($criterion['descriptionmarkers'], $criterion['descriptionmarkersformat']),
array('class'=>'criteriondescriptionmarkers'.$descmarkerclass, 'name' => '{NAME}[criteria][{CRITERION-id}][descriptionmarkers]')); $maxscore = html_writer::tag('div', s($criterion['maxscore']), array('class'=>'criteriondescriptionscore', 'name' => '{NAME}[criteria][{CRITERION-id}][maxscore]')); // Retain newlines as <br> tags when displaying the marking guide. $description = nl2br($description); $descriptionmarkers = nl2br($descriptionmarkers); } if (isset($criterion['error_description'])) { $descriptionclass .= ' error'; } $title = $shortname; if ($mode == gradingform_guide_controller::DISPLAY_EDIT_FULL || $mode == gradingform_guide_controller::DISPLAY_PREVIEW) { $title .= html_writer::tag('label', get_string('descriptionstudents', 'gradingform_guide'), array('for'=>'{NAME}[criteria][{CRITERION-id}][description]')); $title .= $description; $title .= html_writer::tag('label', get_string('descriptionmarkers', 'gradingform_guide'), array('for'=>'{NAME}[criteria][{CRITERION-id}][descriptionmarkers]')); $title .= $descriptionmarkers; $title .= html_writer::tag('label', get_string('maxscore', 'gradingform_guide'), array('for'=>'{NAME}[criteria][{CRITERION-id}][maxscore]')); $title .= $maxscore; } else if ($mode == gradingform_guide_controller::DISPLAY_PREVIEW_GRADED || $mode == gradingform_guide_controller::DISPLAY_VIEW) { $title .= $description; if (!empty($options['showmarkspercriterionstudents'])) { $title .= html_writer::label(get_string('maxscore', 'gradingform_guide'), null); $title .= $maxscore; } } else { $title .= $description . $descriptionmarkers; } // Title cell params. $titletdparams = array( 'class' => $descriptionclass, 'id' => '{NAME}-criteria-{CRITERION-id}-shortname-cell' ); if ($mode != gradingform_guide_controller::DISPLAY_EDIT_FULL && $mode != gradingform_guide_controller::DISPLAY_EDIT_FROZEN) { // Set description's cell as tab-focusable. $titletdparams['tabindex'] = '0'; } $criteriontemplate .= html_writer::tag('td', $title, $titletdparams); $currentremark = ''; $currentscore = ''; if (isset($value['remark'])) { $currentremark = $value['remark']; } if (isset($value['score'])) { $currentscore = $value['score']; } // Element ID of the remark text area. $remarkid = $elementname . '-criteria-' . $criterion['id'] . '-remark'; if ($mode == gradingform_guide_controller::DISPLAY_EVAL) { $scoreclass = ''; if (!empty($validationerrors[$criterion['id']]['score'])) { $scoreclass = 'error'; $currentscore = $validationerrors[$criterion['id']]['score']; // Show invalid score in form. } // Grading remark text area parameters. $remarkparams = array( 'name' => '{NAME}[criteria][{CRITERION-id}][remark]', 'id' => $remarkid, 'cols' => '65', 'rows' => '5', 'class' => 'markingguideremark form-control', 'aria-labelledby' => '{NAME}-remarklabel{CRITERION-id}' ); // Grading remark text area. $input = html_writer::tag('textarea', s($currentremark), $remarkparams); // Show the frequently-used comments chooser only if there are defined entries. $commentchooser = ''; if (!empty($comments)) { // Frequently used comments chooser. $chooserbuttonid = 'criteria-' . $criterion['id'] . '-commentchooser'; $commentchooserparams = array('id' => $chooserbuttonid, 'class' => 'commentchooser btn btn-secondary'); $commentchooser = html_writer::tag('button', get_string('insertcomment', 'gradingform_guide'), $commentchooserparams); // Option items for the frequently used comments chooser dialog. $commentoptions = array(); foreach ($comments as $id => $comment) { $commentoption = new stdClass(); $commentoption->id = $id;
< $commentoption->description = $comment['description'];
> $commentoption->description = html_to_text(format_text($comment['description'], $comment['descriptionformat']));
$commentoptions[] = $commentoption; } // Include string for JS for the comment chooser title. $this->page->requires->string_for_js('insertcomment', 'gradingform_guide'); // Include comment_chooser module. $this->page->requires->js_call_amd('gradingform_guide/comment_chooser', 'initialise', array($criterion['id'], $chooserbuttonid, $remarkid, $commentoptions)); } // Hidden marking guide remark label. $remarklabelparams = array( 'class' => 'hidden', 'id' => '{NAME}-remarklabel{CRITERION-id}' );
< $remarklabeltext = get_string('criterionremark', 'gradingform_guide', $criterion['shortname']);
> $remarklabeltext = get_string('criterionremark', 'gradingform_guide', > format_text($criterion['shortname'], FORMAT_HTML));
$remarklabel = html_writer::label($remarklabeltext, $remarkid, false, $remarklabelparams); $criteriontemplate .= html_writer::tag('td', $remarklabel . $input . $commentchooser, array('class' => 'remark')); // Score input and max score. $scoreinputparams = array( 'type' => 'text', 'name' => '{NAME}[criteria][{CRITERION-id}][score]', 'class' => $scoreclass . ' form-control', 'id' => '{NAME}-criteria-{CRITERION-id}-score', 'size' => '3', 'value' => $currentscore, 'aria-labelledby' => '{NAME}-score-label' ); $score = html_writer::empty_tag('input', $scoreinputparams); $score .= html_writer::div('/' . s($criterion['maxscore'])); $criteriontemplate .= html_writer::tag('td', $score, array('class' => 'score')); } else if ($mode == gradingform_guide_controller::DISPLAY_EVAL_FROZEN) { $criteriontemplate .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => '{NAME}[criteria][{CRITERION-id}][remark]', 'value' => $currentremark)); } else if ($mode == gradingform_guide_controller::DISPLAY_REVIEW || $mode == gradingform_guide_controller::DISPLAY_VIEW) { // Hidden marking guide remark description. $remarkdescparams = array( 'id' => '{NAME}-criteria-{CRITERION-id}-remark-desc' ); $remarkdesctext = get_string('criterionremark', 'gradingform_guide', $criterion['shortname']); $remarkdesc = html_writer::div($remarkdesctext, 'hidden', $remarkdescparams); // Remarks cell. $remarkdiv = html_writer::div(s($currentremark)); $remarkcellparams = array( 'class' => 'remark', 'tabindex' => '0', 'id' => '{NAME}-criteria-{CRITERION-id}-remark', 'aria-describedby' => '{NAME}-criteria-{CRITERION-id}-remark-desc' ); $criteriontemplate .= html_writer::tag('td', $remarkdesc . $remarkdiv, $remarkcellparams); // Score cell. if (!empty($options['showmarkspercriterionstudents'])) { $scorecellparams = array( 'class' => 'score', 'tabindex' => '0', 'id' => '{NAME}-criteria-{CRITERION-id}-score', 'aria-describedby' => '{NAME}-score-label' ); $scorediv = html_writer::div(s($currentscore) . ' / ' . s($criterion['maxscore'])); $criteriontemplate .= html_writer::tag('td', $scorediv, $scorecellparams); } } $criteriontemplate .= html_writer::end_tag('tr'); // Criterion. $criteriontemplate = str_replace('{NAME}', $elementname, $criteriontemplate); $criteriontemplate = str_replace('{CRITERION-id}', $criterion['id'], $criteriontemplate); return $criteriontemplate; } /** * This function returns html code for displaying criterion. Depending on $mode it may be the * code to edit guide, to preview the guide, to evaluate somebody or to review the evaluation. * * This function may be called from display_guide() to display the whole guide, or it can be * called by itself to return a template used by JavaScript to add new empty criteria to the * guide being designed. * In this case it will use macros like {NAME}, {LEVELS}, {CRITERION-id}, etc. * * When overriding this function it is very important to remember that all elements of html * form (in edit or evaluate mode) must have the name $elementname. * * Also JavaScript relies on the class names of elements and when developer changes them * script might stop working. * * @param int $mode guide display mode, one of gradingform_guide_controller::DISPLAY_* {@link gradingform_guide_controller} * @param string $elementname the name of the form element (in editor mode) or the prefix for div ids (in view mode) * @param array $comment * @return string */ public function comment_template($mode, $elementname = '{NAME}', $comment = null) { if ($comment === null || !is_array($comment) || !array_key_exists('id', $comment)) { $comment = array('id' => '{COMMENT-id}', 'description' => '{COMMENT-description}', 'sortorder' => '{COMMENT-sortorder}', 'class' => '{COMMENT-class}'); } else { foreach (array('sortorder', 'description', 'class') as $key) { // Set missing array elements to empty strings to avoid warnings. if (!array_key_exists($key, $comment)) { $criterion[$key] = ''; } } } $commenttemplate = html_writer::start_tag('tr', array('class' => 'criterion'. $comment['class'], 'id' => '{NAME}-comments-{COMMENT-id}')); if ($mode == gradingform_guide_controller::DISPLAY_EDIT_FULL) { $commenttemplate .= html_writer::start_tag('td', array('class' => 'controls')); foreach (array('moveup', 'delete', 'movedown') as $key) { $value = get_string('comments'.$key, 'gradingform_guide'); $button = html_writer::empty_tag('input', array('type' => 'submit', 'name' => '{NAME}[comments][{COMMENT-id}]['.$key.']', 'id' => '{NAME}-comments-{COMMENT-id}-'.$key, 'value' => $value, 'title' => $value)); $commenttemplate .= html_writer::tag('div', $button, array('class' => $key)); } $commenttemplate .= html_writer::end_tag('td'); // Controls. $commenttemplate .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => '{NAME}[comments][{COMMENT-id}][sortorder]', 'value' => $comment['sortorder'])); $description = html_writer::tag('textarea', s($comment['description']), array('name' => '{NAME}[comments][{COMMENT-id}][description]', 'id' => '{NAME}-comments-{COMMENT-id}-description', 'aria-labelledby' => '{NAME}-comment-label', 'cols' => '65', 'rows' => '5')); $description = html_writer::tag('div', $description, array('class'=>'criteriondesc')); } else { if ($mode == gradingform_guide_controller::DISPLAY_EDIT_FROZEN) { $commenttemplate .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => '{NAME}[comments][{COMMENT-id}][sortorder]', 'value' => $comment['sortorder'])); $commenttemplate .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => '{NAME}[comments][{COMMENT-id}][description]', 'value' => $comment['description'])); } if ($mode == gradingform_guide_controller::DISPLAY_EVAL) { $description = html_writer::tag('span', s($comment['description']), array('name' => '{NAME}[comments][{COMMENT-id}][description]', 'title' => get_string('clicktocopy', 'gradingform_guide'), 'id' => '{NAME}[comments][{COMMENT-id}]', 'class'=>'markingguidecomment')); } else {
< $description = s($comment['description']);
> $description = format_text($comment['description'], $comment['descriptionformat']);
} // Retain newlines as <br> tags when displaying 'frequently used comments'. $description = nl2br($description); } $descriptionclass = 'description'; if (isset($comment['error_description'])) { $descriptionclass .= ' error'; } $descriptioncellparams = array( 'class' => $descriptionclass, 'id' => '{NAME}-comments-{COMMENT-id}-description-cell' ); // Make description cell tab-focusable when in review mode. if ($mode != gradingform_guide_controller::DISPLAY_EDIT_FULL && $mode != gradingform_guide_controller::DISPLAY_EDIT_FROZEN) { $descriptioncellparams['tabindex'] = '0'; } $commenttemplate .= html_writer::tag('td', $description, $descriptioncellparams); $commenttemplate .= html_writer::end_tag('tr'); // Criterion. $commenttemplate = str_replace('{NAME}', $elementname, $commenttemplate); $commenttemplate = str_replace('{COMMENT-id}', $comment['id'], $commenttemplate); return $commenttemplate; } /** * This function returns html code for displaying guide template (content before and after * criteria list). Depending on $mode it may be the code to edit guide, to preview the guide, * to evaluate somebody or to review the evaluation. * * This function is called from display_guide() to display the whole guide. * * When overriding this function it is very important to remember that all elements of html * form (in edit or evaluate mode) must have the name $elementname. * * Also JavaScript relies on the class names of elements and when developer changes them * script might stop working. * * @param int $mode guide display mode, one of gradingform_guide_controller::DISPLAY_* {@link gradingform_guide_controller} * @param array $options An array of options provided to {@link gradingform_guide_renderer::guide_edit_options()} * @param string $elementname the name of the form element (in editor mode) or the prefix for div ids (in view mode) * @param string $criteriastr evaluated templates for this guide's criteria * @param string $commentstr * @return string */ protected function guide_template($mode, $options, $elementname, $criteriastr, $commentstr) { $classsuffix = ''; // CSS suffix for class of the main div. Depends on the mode. switch ($mode) { case gradingform_guide_controller::DISPLAY_EDIT_FULL: $classsuffix = ' editor editable'; break; case gradingform_guide_controller::DISPLAY_EDIT_FROZEN: $classsuffix = ' editor frozen'; break; case gradingform_guide_controller::DISPLAY_PREVIEW: case gradingform_guide_controller::DISPLAY_PREVIEW_GRADED: $classsuffix = ' editor preview'; break; case gradingform_guide_controller::DISPLAY_EVAL: $classsuffix = ' evaluate editable'; break; case gradingform_guide_controller::DISPLAY_EVAL_FROZEN: $classsuffix = ' evaluate frozen'; break; case gradingform_guide_controller::DISPLAY_REVIEW: $classsuffix = ' review'; break; case gradingform_guide_controller::DISPLAY_VIEW: $classsuffix = ' view'; break; } $guidetemplate = html_writer::start_tag('div', array('id' => 'guide-{NAME}', 'class' => 'clearfix gradingform_guide'.$classsuffix)); // Hidden guide label. $guidedescparams = array( 'id' => 'guide-{NAME}-desc', 'aria-hidden' => 'true' ); $guidetemplate .= html_writer::div(get_string('guide', 'gradingform_guide'), 'hidden', $guidedescparams); // Hidden criterion name label/description. $guidetemplate .= html_writer::div(get_string('criterionname', 'gradingform_guide'), 'hidden', array('id' => '{NAME}-criterion-name-label')); // Hidden score label/description. $guidetemplate .= html_writer::div(get_string('score', 'gradingform_guide'), 'hidden', array('id' => '{NAME}-score-label')); // Criteria table parameters. $criteriatableparams = array( 'class' => 'criteria', 'id' => '{NAME}-criteria', 'aria-describedby' => 'guide-{NAME}-desc'); $guidetemplate .= html_writer::tag('table', $criteriastr, $criteriatableparams); if ($mode == gradingform_guide_controller::DISPLAY_EDIT_FULL) { $value = get_string('addcriterion', 'gradingform_guide'); $input = html_writer::empty_tag('input', array('type' => 'submit', 'name' => '{NAME}[criteria][addcriterion]', 'id' => '{NAME}-criteria-addcriterion', 'value' => $value, 'title' => $value)); $guidetemplate .= html_writer::tag('div', $input, array('class' => 'addcriterion')); } if (!empty($commentstr)) { $guidetemplate .= html_writer::div(get_string('comments', 'gradingform_guide'), 'commentheader', array('id' => '{NAME}-comments-label')); $guidetemplate .= html_writer::div(get_string('comment', 'gradingform_guide'), 'hidden', array('id' => '{NAME}-comment-label', 'aria-hidden' => 'true')); $commentstableparams = array( 'class' => 'comments', 'id' => '{NAME}-comments', 'aria-describedby' => '{NAME}-comments-label'); $guidetemplate .= html_writer::tag('table', $commentstr, $commentstableparams); } if ($mode == gradingform_guide_controller::DISPLAY_EDIT_FULL) { $value = get_string('addcomment', 'gradingform_guide'); $input = html_writer::empty_tag('input', array('type' => 'submit', 'name' => '{NAME}[comments][addcomment]', 'id' => '{NAME}-comments-addcomment', 'value' => $value, 'title' => $value)); $guidetemplate .= html_writer::tag('div', $input, array('class' => 'addcomment')); } $guidetemplate .= $this->guide_edit_options($mode, $options); $guidetemplate .= html_writer::end_tag('div'); return str_replace('{NAME}', $elementname, $guidetemplate); } /** * Generates html template to view/edit the guide options. Expression {NAME} is used in * template for the form element name * * @param int $mode guide display mode, one of gradingform_guide_controller::DISPLAY_* {@link gradingform_guide_controller} * @param array $options * @return string */ protected function guide_edit_options($mode, $options) { if ($mode != gradingform_guide_controller::DISPLAY_EDIT_FULL && $mode != gradingform_guide_controller::DISPLAY_EDIT_FROZEN && $mode != gradingform_guide_controller::DISPLAY_PREVIEW) { // Options are displayed only for people who can manage. return; } $html = html_writer::start_tag('div', array('class' => 'options')); $html .= html_writer::tag('div', get_string('guideoptions', 'gradingform_guide'), array('class' => 'optionsheading')); $attrs = array('type' => 'hidden', 'name' => '{NAME}[options][optionsset]', 'value' => 1, 'class' => 'form-control'); $html .= html_writer::empty_tag('input', $attrs); foreach ($options as $option => $value) { $html .= html_writer::start_tag('div', array('class' => 'option '.$option)); $attrs = array('name' => '{NAME}[options]['.$option.']', 'id' => '{NAME}-options-'.$option); switch ($option) { case 'sortlevelsasc': // Display option as dropdown. $html .= html_writer::tag('span', get_string($option, 'gradingform_guide'), array('class' => 'label')); $value = (int)(!!$value); // Make sure $value is either 0 or 1. if ($mode == gradingform_guide_controller::DISPLAY_EDIT_FULL) { $selectoptions = array(0 => get_string($option.'0', 'gradingform_guide'), 1 => get_string($option.'1', 'gradingform_guide')); $valuestr = html_writer::select($selectoptions, $attrs['name'], $value, false, array('id' => $attrs['id'])); $html .= html_writer::tag('span', $valuestr, array('class' => 'value')); // TODO add here button 'Sort levels'. } else { $html .= html_writer::tag('span', get_string($option.$value, 'gradingform_guide'), array('class' => 'value')); if ($mode == gradingform_guide_controller::DISPLAY_EDIT_FROZEN) { $html .= html_writer::empty_tag('input', $attrs + array('type' => 'hidden', 'value' => $value)); } } break; default: if ($mode == gradingform_guide_controller::DISPLAY_EDIT_FROZEN && $value) { $html .= html_writer::empty_tag('input', $attrs + array('type' => 'hidden', 'value' => $value)); } // Display option as checkbox. $attrs['type'] = 'checkbox'; $attrs['value'] = 1; if ($value) { $attrs['checked'] = 'checked'; } if ($mode == gradingform_guide_controller::DISPLAY_EDIT_FROZEN || $mode == gradingform_guide_controller::DISPLAY_PREVIEW) { $attrs['disabled'] = 'disabled'; unset($attrs['name']); } $html .= html_writer::empty_tag('input', $attrs); $html .= html_writer::tag('label', get_string($option, 'gradingform_guide'), array('for' => $attrs['id'])); break; } $html .= html_writer::end_tag('div'); // Option. } $html .= html_writer::end_tag('div'); // Options. return $html; } /** * This function returns html code for displaying guide. Depending on $mode it may be the code * to edit guide, to preview the guide, to evaluate somebody or to review the evaluation. * * It is very unlikely that this function needs to be overriden by theme. It does not produce * any html code, it just prepares data about guide design and evaluation, adds the CSS * class to elements and calls the functions level_template, criterion_template and * guide_template * * @param array $criteria data about the guide design * @param array $comments * @param array $options * @param int $mode guide display mode, one of gradingform_guide_controller::DISPLAY_* {@link gradingform_guide_controller} * @param string $elementname the name of the form element (in editor mode) or the prefix for div ids (in view mode) * @param array $values evaluation result * @param array $validationerrors * @return string */ public function display_guide($criteria, $comments, $options, $mode, $elementname = null, $values = null, $validationerrors = null) { $criteriastr = ''; $cnt = 0; foreach ($criteria as $id => $criterion) { $criterion['class'] = $this->get_css_class_suffix($cnt++, count($criteria) -1); $criterion['id'] = $id; if (isset($values['criteria'][$id])) { $criterionvalue = $values['criteria'][$id]; } else { $criterionvalue = null; } $criteriastr .= $this->criterion_template($mode, $options, $elementname, $criterion, $criterionvalue, $validationerrors, $comments); } $cnt = 0; $commentstr = ''; // Check if comments should be displayed. if ($mode == gradingform_guide_controller::DISPLAY_EDIT_FULL || $mode == gradingform_guide_controller::DISPLAY_EDIT_FROZEN || $mode == gradingform_guide_controller::DISPLAY_PREVIEW || $mode == gradingform_guide_controller::DISPLAY_EVAL_FROZEN) { foreach ($comments as $id => $comment) { $comment['id'] = $id; $comment['class'] = $this->get_css_class_suffix($cnt++, count($comments) -1); $commentstr .= $this->comment_template($mode, $elementname, $comment); } } $output = $this->guide_template($mode, $options, $elementname, $criteriastr, $commentstr); if ($mode == gradingform_guide_controller::DISPLAY_EVAL) { $showdesc = get_user_preferences('gradingform_guide-showmarkerdesc', true); $showdescstud = get_user_preferences('gradingform_guide-showstudentdesc', true); $checked1 = array(); $checked2 = array(); $checked_s1 = array(); $checked_s2 = array(); $checked = array('checked' => 'checked'); if ($showdesc) { $checked1 = $checked; } else { $checked2 = $checked; } if ($showdescstud) { $checked_s1 = $checked; } else { $checked_s2 = $checked; } $radio1 = html_writer::tag('input', get_string('showmarkerdesc', 'gradingform_guide'), array('type' => 'radio', 'name' => 'showmarkerdesc', 'value' => "true")+$checked1); $radio1 = html_writer::tag('label', $radio1); $radio2 = html_writer::tag('input', get_string('hidemarkerdesc', 'gradingform_guide'), array('type' => 'radio', 'name' => 'showmarkerdesc', 'value' => "false")+$checked2); $radio2 = html_writer::tag('label', $radio2); $output .= html_writer::tag('div', $radio1 . $radio2, array('class' => 'showmarkerdesc')); $radio1 = html_writer::tag('input', get_string('showstudentdesc', 'gradingform_guide'), array('type' => 'radio', 'name' => 'showstudentdesc', 'value' => "true")+$checked_s1); $radio1 = html_writer::tag('label', $radio1); $radio2 = html_writer::tag('input', get_string('hidestudentdesc', 'gradingform_guide'), array('type' => 'radio', 'name' => 'showstudentdesc', 'value' => "false")+$checked_s2); $radio2 = html_writer::tag('label', $radio2); $output .= html_writer::tag('div', $radio1 . $radio2, array('class' => 'showstudentdesc')); } return $output; } /** * Help function to return CSS class names for element (first/last/even/odd) with leading space * * @param int $idx index of this element in the row/column * @param int $maxidx maximum index of the element in the row/column * @return string */ protected function get_css_class_suffix($idx, $maxidx) { $class = ''; if ($idx == 0) { $class .= ' first'; } if ($idx == $maxidx) { $class .= ' last'; } if ($idx % 2) { $class .= ' odd'; } else { $class .= ' even'; } return $class; } /** * Displays for the student the list of instances or default content if no instances found * * @param array $instances array of objects of type gradingform_guide_instance * @param string $defaultcontent default string that would be displayed without advanced grading * @param bool $cangrade whether current user has capability to grade in this context * @return string */ public function display_instances($instances, $defaultcontent, $cangrade) { $return = ''; if (count($instances)) { $return .= html_writer::start_tag('div', array('class' => 'advancedgrade')); $idx = 0; foreach ($instances as $instance) { $return .= $this->display_instance($instance, $idx++, $cangrade); } $return .= html_writer::end_tag('div'); } return $return. $defaultcontent; } /** * Displays one grading instance * * @param gradingform_guide_instance $instance * @param int $idx unique number of instance on page * @param bool $cangrade whether current user has capability to grade in this context */ public function display_instance(gradingform_guide_instance $instance, $idx, $cangrade) { $criteria = $instance->get_controller()->get_definition()->guide_criteria; $options = $instance->get_controller()->get_options(); $values = $instance->get_guide_filling(); if ($cangrade) { $mode = gradingform_guide_controller::DISPLAY_REVIEW; } else { $mode = gradingform_guide_controller::DISPLAY_VIEW; } $output = $this->box($instance->get_controller()->get_formatted_description(), 'gradingform_guide-description'). $this->display_guide($criteria, array(), $options, $mode, 'guide'.$idx, $values); return $output; } /** * Displays a confirmation message after a regrade has occured * * @param string $elementname * @param int $changelevel * @param int $value The regrade option that was used * @return string */ public function display_regrade_confirmation($elementname, $changelevel, $value) { $html = html_writer::start_tag('div', array('class' => 'gradingform_guide-regrade', 'role' => 'alert')); if ($changelevel<=2) { $html .= get_string('regrademessage1', 'gradingform_guide'); $selectoptions = array( 0 => get_string('regradeoption0', 'gradingform_guide'), 1 => get_string('regradeoption1', 'gradingform_guide') ); $html .= html_writer::select($selectoptions, $elementname.'[regrade]', $value, false); } else { $html .= get_string('regrademessage5', 'gradingform_guide'); $html .= html_writer::empty_tag('input', array('name' => $elementname.'[regrade]', 'value' => 1, 'type' => 'hidden')); } $html .= html_writer::end_tag('div'); return $html; } /** * Generates and returns HTML code to display information box about how guide score is converted to the grade * * @param array $scores * @return string */ public function display_guide_mapping_explained($scores) { $html = ''; if (!$scores) { return $html; } if (isset($scores['modulegrade']) && $scores['maxscore'] != $scores['modulegrade']) { $html .= $this->box(html_writer::tag('div', get_string('guidemappingexplained', 'gradingform_guide', (object)$scores)) , 'generalbox gradingform_guide-error'); } return $html; } }