From 39c6f4b6258a5dba2ea21a4bd0e464c7b461621b Mon Sep 17 00:00:00 2001 From: Marina Glancy Date: Wed, 26 Oct 2011 11:36:29 +0800 Subject: [PATCH] MDL-29482, MDL-29481: better rendering, options for rubric display --- grade/grading/form/rubric/edit_form.php | 6 +- grade/grading/form/rubric/js/rubriceditor.js | 38 ++-- .../rubric/lang/en/gradingform_rubric.php | 15 +- grade/grading/form/rubric/lib.php | 66 +++++-- grade/grading/form/rubric/renderer.php | 165 +++++++++++++----- grade/grading/form/rubric/rubriceditor.php | 75 +++++--- grade/grading/form/rubric/styles.css | 47 +++-- 7 files changed, 296 insertions(+), 116 deletions(-) diff --git a/grade/grading/form/rubric/edit_form.php b/grade/grading/form/rubric/edit_form.php index ba234a199d3..1341dc48c89 100644 --- a/grade/grading/form/rubric/edit_form.php +++ b/grade/grading/form/rubric/edit_form.php @@ -57,9 +57,9 @@ class gradingform_rubric_editrubric extends moodleform { $form->setType('description_editor', PARAM_RAW); // rubric editor - $element = $form->addElement('rubriceditor', 'rubric_criteria', 'Rubric 1'); // todo label - $form->setType('rubric_criteria', PARAM_RAW); - $form->addRule('rubric_criteria', '', 'rubriceditorcompleted'); //TODO how to add this rule automatically????? + $element = $form->addElement('rubriceditor', 'rubric', get_string('rubric', 'gradingform_rubric')); + $form->setType('rubric', PARAM_RAW); + $form->addRule('rubric', '', 'rubriceditorcompleted'); //TODO how to add this rule automatically????? if (array_key_exists('freezerubric', $this->_customdata) && $this->_customdata['freezerubric']) { $element->freeze(); } diff --git a/grade/grading/form/rubric/js/rubriceditor.js b/grade/grading/form/rubric/js/rubriceditor.js index 64da044c5f5..4d1fc763787 100644 --- a/grade/grading/form/rubric/js/rubriceditor.js +++ b/grade/grading/form/rubric/js/rubriceditor.js @@ -92,10 +92,10 @@ M.gradingform_rubriceditor.buttonclick = function(e, Y, name, confirmed) { if (e.target.get('type') != 'submit') return; var chunks = e.target.get('id').split('-'), action = chunks[chunks.length-1] - if (chunks[0] != name) return; + if (chunks[0] != name || chunks[1] != 'criteria') return; var elements_str - if (chunks.length>3 || action == 'addlevel') { - elements_str = '#rubric-'+name+' #'+name+'-'+chunks[1]+'-levels .level' + if (chunks.length>4 || action == 'addlevel') { + elements_str = '#rubric-'+name+' #'+name+'-criteria-'+chunks[2]+'-levels .level' } else { elements_str = '#rubric-'+name+' .criterion' } @@ -112,38 +112,44 @@ M.gradingform_rubriceditor.buttonclick = function(e, Y, name, confirmed) { 'callbackargs' : [e, Y, name, true], 'callback' : M.gradingform_rubriceditor.buttonclick }; - if (chunks.length == 2 && action == 'addcriterion') { + if (chunks.length == 3 && action == 'addcriterion') { // ADD NEW CRITERION var newcriterion = M.gradingform_rubriceditor.templates[name]['criterion']. replace(/\{CRITERION-id\}/g, 'NEWID'+newid).replace(/\{.+?\}/g, '') - Y.one('#'+name+'-criteria').append(newcriterion) + var parentel = Y.one('#'+name+'-criteria') + if (parentel.one('>tbody')) parentel = parentel.one('>tbody') + parentel.append(newcriterion) M.gradingform_rubriceditor.addhandlers(Y, name); - } else if (chunks.length == 4 && action == 'addlevel') { + } else if (chunks.length == 5 && action == 'addlevel') { // ADD NEW LEVEL var newlevel = M.gradingform_rubriceditor.templates[name]['level']. - replace(/\{CRITERION-id\}/g, chunks[1]).replace(/\{LEVEL-id\}/g, 'NEWID'+newid).replace(/\{.+?\}/g, '') - Y.one('#'+name+'-'+chunks[1]+'-levels').append(newlevel) + replace(/\{CRITERION-id\}/g, chunks[2]).replace(/\{LEVEL-id\}/g, 'NEWID'+newid).replace(/\{.+?\}/g, '') + Y.one('#'+name+'-criteria-'+chunks[2]+'-levels').append(newlevel) + var levels = Y.all('#'+name+'-criteria-'+chunks[2]+'-levels .level') + if (levels.size()) levels.set('width', Math.round(100/levels.size())+'%') M.gradingform_rubriceditor.addhandlers(Y, name); - } else if (chunks.length == 3 && action == 'moveup') { + } else if (chunks.length == 4 && action == 'moveup') { // MOVE CRITERION UP - el = Y.one('#'+name+'-'+chunks[1]) + el = Y.one('#'+name+'-criteria-'+chunks[2]) if (el.previous()) el.get('parentNode').insertBefore(el, el.previous()) - } else if (chunks.length == 3 && action == 'movedown') { + } else if (chunks.length == 4 && action == 'movedown') { // MOVE CRITERION DOWN - el = Y.one('#'+name+'-'+chunks[1]) + el = Y.one('#'+name+'-criteria-'+chunks[2]) if (el.next()) el.get('parentNode').insertBefore(el.next(), el) - } else if (chunks.length == 3 && action == 'delete') { + } else if (chunks.length == 4 && action == 'delete') { // DELETE CRITERION if (confirmed) { - Y.one('#'+name+'-'+chunks[1]).remove() + Y.one('#'+name+'-criteria-'+chunks[2]).remove() } else { dialog_options['message'] = M.str.gradingform_rubric.confirmdeletecriterion M.util.show_confirm_dialog(e, dialog_options); } - } else if (chunks.length == 5 && action == 'delete') { + } else if (chunks.length == 6 && action == 'delete') { // DELETE LEVEL if (confirmed) { - Y.one('#'+name+'-'+chunks[1]+'-'+chunks[2]+'-'+chunks[3]).remove() + Y.one('#'+name+'-criteria-'+chunks[2]+'-'+chunks[3]+'-'+chunks[4]).remove() + levels = Y.all('#'+name+'-criteria-'+chunks[2]+'-levels .level') + if (levels.size()) levels.set('width', Math.round(100/levels.size())+'%') } else { dialog_options['message'] = M.str.gradingform_rubric.confirmdeletelevel M.util.show_confirm_dialog(e, dialog_options); diff --git a/grade/grading/form/rubric/lang/en/gradingform_rubric.php b/grade/grading/form/rubric/lang/en/gradingform_rubric.php index a634486d330..21b2bbbd43b 100644 --- a/grade/grading/form/rubric/lang/en/gradingform_rubric.php +++ b/grade/grading/form/rubric/lang/en/gradingform_rubric.php @@ -37,8 +37,21 @@ $string['criterionmoveup'] = 'Move up'; $string['criteriondelete'] = 'Delete criterion'; $string['criterionmovedown'] = 'Move down'; $string['criterionaddlevel'] = 'Add level'; -$string['scorepostfix'] = ' pts'; +$string['scorepostfix'] = ' points'; $string['leveldelete'] = 'Delete level'; $string['criterionempty'] = 'Click to edit criterion'; $string['levelempty'] = 'Click to edit level'; + +$string['rubric'] = 'Rubric'; +$string['rubricoptions'] = 'Rubric options'; + +$string['sortlevelsasc'] = 'Sort order for levels:'; +$string['sortlevelsasc1'] = 'Ascending by number of points'; +$string['sortlevelsasc0'] = 'Descending by number of points'; +$string['showdescriptionteacher'] = 'Display rubric description during evaluation'; +$string['showdescriptionstudent'] = 'Display rubric description to those being graded'; +$string['showscoreteacher'] = 'Display points for each level during evaluation'; +$string['showscorestudent'] = 'Display points for each level to those being graded'; +$string['enableremarks'] = 'Allow grader to add text remarks for each criteria'; +$string['showremarksstudent'] = 'Show remarks to those being graded'; diff --git a/grade/grading/form/rubric/lib.php b/grade/grading/form/rubric/lib.php index 52ee286e586..63e08acf084 100644 --- a/grade/grading/form/rubric/lib.php +++ b/grade/grading/form/rubric/lib.php @@ -38,7 +38,8 @@ class gradingform_rubric_controller extends gradingform_controller { const DISPLAY_PREVIEW = 3; // Preview the rubric design const DISPLAY_EVAL = 4; // For evaluation, enabled (teacher grades a student) const DISPLAY_EVAL_FROZEN = 5; // For evaluation, with hidden fields - const DISPLAY_REVIEW = 6; // Dispaly filled rubric (i.e. students see their grades) + const DISPLAY_REVIEW = 6; // Teacher reviews filled rubric + const DISPLAY_VIEW = 7; // Dispaly filled rubric (i.e. students see their grades) /** * Extends the module settings navigation with the rubric grading settings @@ -73,8 +74,12 @@ class gradingform_rubric_controller extends gradingform_controller { parent::update_definition((object)array('descriptionformat' => FORMAT_MOODLE), $usermodified); parent::load_definition(); } - $options = self::description_form_field_options($this->get_context()); - $newdefinition = file_postupdate_standard_editor($newdefinition, 'description', $options, $this->get_context(), + if (!isset($newdefinition->rubric['options'])) { + $newdefinition->rubric['options'] = self::get_default_options(); + } + $newdefinition->options = json_encode($newdefinition->rubric['options']); + $editoroptions = self::description_form_field_options($this->get_context()); + $newdefinition = file_postupdate_standard_editor($newdefinition, 'description', $editoroptions, $this->get_context(), 'gradingform_rubric', 'definition_description', $this->definition->id); parent::update_definition($newdefinition, $usermodified); @@ -83,10 +88,10 @@ class gradingform_rubric_controller extends gradingform_controller { // update rubric data $haschanges = false; - if (empty($newdefinition->rubric_criteria)) { + if (empty($newdefinition->rubric['criteria'])) { $newcriteria = array(); } else { - $newcriteria = $newdefinition->rubric_criteria; // new ones to be saved + $newcriteria = $newdefinition->rubric['criteria']; // new ones to be saved } $currentcriteria = $currentdefinition->rubric_criteria; $criteriafields = array('sortorder', 'description', 'descriptionformat'); @@ -175,7 +180,6 @@ class gradingform_rubric_controller extends gradingform_controller { */ protected function load_definition() { global $DB; - $sql = "SELECT gd.*, rc.id AS rcid, rc.sortorder AS rcsortorder, rc.description AS rcdescription, rc.descriptionformat AS rcdescriptionformat, rl.id AS rlid, rl.score AS rlscore, rl.definition AS rldefinition, rl.definitionformat AS rldefinitionformat @@ -213,6 +217,37 @@ class gradingform_rubric_controller extends gradingform_controller { } } $rs->close(); + $options = $this->get_options(); + if (!$options['sortlevelsasc']) { + foreach (array_keys($this->definition->rubric_criteria) as $rcid) { + $this->definition->rubric_criteria[$rcid]['levels'] = array_reverse($this->definition->rubric_criteria[$rcid]['levels'], true); + } + } + } + + public static function get_default_options() { + $options = array( + 'sortlevelsasc' => 1, + //'showdescriptionteacher' => 1, + //'showdescriptionstudent' => 1, + 'showscoreteacher' => 1, + 'showscorestudent' => 1, + 'enableremarks' => 1, + 'showremarksstudent' => 1 + ); + // TODO description options + return $options; + } + + public function get_options() { + $options = self::get_default_options(); + if (!empty($this->definition->options)) { + $thisoptions = json_decode($this->definition->options); + foreach ($thisoptions as $option => $value) { + $options[$option] = $value; + } + } + return $options; } /** @@ -226,17 +261,16 @@ class gradingform_rubric_controller extends gradingform_controller { $properties = new stdClass(); $properties->areaid = $this->areaid; if ($definition) { - foreach (array('id', 'name', 'description', 'descriptionformat', 'options', 'status') as $key) { + foreach (array('id', 'name', 'description', 'descriptionformat', 'status') as $key) { $properties->$key = $definition->$key; } $options = self::description_form_field_options($this->get_context()); $properties = file_prepare_standard_editor($properties, 'description', $options, $this->get_context(), 'gradingform_rubric', 'definition_description', $definition->id); } + $properties->rubric = array('criteria' => array(), 'options' => $this->get_options()); if (!empty($definition->rubric_criteria)) { - $properties->rubric_criteria = $definition->rubric_criteria; - } else { - $properties->rubric_criteria = array(); + $properties->rubric['criteria'] = $definition->rubric_criteria; } return $properties; @@ -254,10 +288,10 @@ class gradingform_rubric_controller extends gradingform_controller { $new = parent::get_definition_copy($target); $old = $this->get_definition_for_editing(); $new->description_editor = $old->description_editor; - $new->rubric_criteria = array(); + $new->rubric = array('criteria' => array(), 'options' => $old->rubric['options']); $newcritid = 1; $newlevid = 1; - foreach ($old->rubric_criteria as $oldcritid => $oldcrit) { + foreach ($old->rubric['criteria'] as $oldcritid => $oldcrit) { unset($oldcrit['id']); if (isset($oldcrit['levels'])) { foreach ($oldcrit['levels'] as $oldlevid => $oldlev) { @@ -269,7 +303,7 @@ class gradingform_rubric_controller extends gradingform_controller { } else { $oldcrit['levels'] = array(); } - $new->rubric_criteria['NEWID'.$newcritid] = $oldcrit; + $new->rubric['criteria']['NEWID'.$newcritid] = $oldcrit; $newcritid++; } @@ -338,7 +372,8 @@ class gradingform_rubric_controller extends gradingform_controller { // append the rubric itself, using own renderer $output = $this->get_renderer($page); $criteria = $this->definition->rubric_criteria; - $rubric = $output->display_rubric($criteria, self::DISPLAY_PREVIEW, 'rubric'); + $options = $this->get_options(); + $rubric = $output->display_rubric($criteria, $options, self::DISPLAY_PREVIEW, 'rubric'); return $header . $rubric; } @@ -557,10 +592,11 @@ class gradingform_rubric_instance extends gradingform_instance { } } $criteria = $this->get_controller()->get_definition()->rubric_criteria; + $options = $this->get_controller()->get_options(); $value = $gradingformelement->getValue(); if ($value === null) { $value = $this->get_rubric_filling(); } - return $this->get_controller()->get_renderer($page)->display_rubric($criteria, $mode, $gradingformelement->getName(), $value); + return $this->get_controller()->get_renderer($page)->display_rubric($criteria, $options, $mode, $gradingformelement->getName(), $value); } } \ No newline at end of file diff --git a/grade/grading/form/rubric/renderer.php b/grade/grading/form/rubric/renderer.php index c6ea89c3efd..489977890e0 100644 --- a/grade/grading/form/rubric/renderer.php +++ b/grade/grading/form/rubric/renderer.php @@ -51,7 +51,7 @@ class gradingform_rubric_renderer { * @param array|null $value (only in view mode) teacher's feedback on this criterion * @return string */ - public function criterion_template($mode, $elementname = '{NAME}', $criterion = null, $levels_str = '{LEVELS}', $value = null) { + public function criterion_template($mode, $options, $elementname = '{NAME}', $criterion = null, $levels_str = '{LEVELS}', $value = null) { // TODO description format, remark format 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}'); @@ -63,48 +63,48 @@ class gradingform_rubric_renderer { } } } - $criterion_template = html_writer::start_tag('tr', array('class' => 'clearfix criterion'. $criterion['class'], 'id' => '{NAME}-{CRITERION-id}')); + $criterion_template = html_writer::start_tag('tr', array('class' => 'criterion'. $criterion['class'], 'id' => '{NAME}-criteria-{CRITERION-id}')); if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FULL) { $criterion_template .= html_writer::start_tag('td', array('class' => 'controls')); foreach (array('moveup', 'delete', 'movedown') as $key) { $value = get_string('criterion'.$key, 'gradingform_rubric'); - $button = html_writer::empty_tag('input', array('type' => 'submit', 'name' => '{NAME}[{CRITERION-id}]['.$key.']', - 'id' => '{NAME}-{CRITERION-id}-'.$key, 'value' => $value, 'title' => $value)); + $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)); $criterion_template .= html_writer::tag('div', $button, array('class' => $key)); } $criterion_template .= html_writer::end_tag('td'); // .controls - $criterion_template .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => '{NAME}[{CRITERION-id}][sortorder]', 'value' => $criterion['sortorder'])); - $description = html_writer::tag('textarea', htmlspecialchars($criterion['description']), array('name' => '{NAME}[{CRITERION-id}][description]', 'cols' => '10', 'rows' => '5')); + $criterion_template .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => '{NAME}[criteria][{CRITERION-id}][sortorder]', 'value' => $criterion['sortorder'])); + $description = html_writer::tag('textarea', htmlspecialchars($criterion['description']), array('name' => '{NAME}[criteria][{CRITERION-id}][description]', 'cols' => '10', 'rows' => '5')); } else { if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FROZEN) { - $criterion_template .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => '{NAME}[{CRITERION-id}][sortorder]', 'value' => $criterion['sortorder'])); - $criterion_template .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => '{NAME}[{CRITERION-id}][description]', 'value' => $criterion['description'])); + $criterion_template .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => '{NAME}[criteria][{CRITERION-id}][sortorder]', 'value' => $criterion['sortorder'])); + $criterion_template .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => '{NAME}[criteria][{CRITERION-id}][description]', 'value' => $criterion['description'])); } $description = $criterion['description']; } - $criterion_template .= html_writer::tag('td', $description, array('class' => 'description', 'id' => '{NAME}-{CRITERION-id}-description')); - $levels_str_table = html_writer::tag('table', html_writer::tag('tr', $levels_str, array('id' => '{NAME}-{CRITERION-id}-levels'))); - $criterion_template .= html_writer::tag('td', $levels_str_table, array('class' => 'clearfix levels')); + $criterion_template .= html_writer::tag('td', $description, array('class' => 'description', 'id' => '{NAME}-criteria-{CRITERION-id}-description')); + $levels_str_table = html_writer::tag('table', html_writer::tag('tr', $levels_str, array('id' => '{NAME}-criteria-{CRITERION-id}-levels'))); + $criterion_template .= html_writer::tag('td', $levels_str_table, array('class' => 'levels')); if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FULL) { $value = get_string('criterionaddlevel', 'gradingform_rubric'); - $button = html_writer::empty_tag('input', array('type' => 'submit', 'name' => '{NAME}[{CRITERION-id}][levels][addlevel]', - 'id' => '{NAME}-{CRITERION-id}-levels-addlevel', 'value' => $value, 'title' => $value)); //TODO '{NAME}-{CRITERION-id}-levels-addlevel + $button = html_writer::empty_tag('input', array('type' => 'submit', 'name' => '{NAME}[criteria][{CRITERION-id}][levels][addlevel]', + 'id' => '{NAME}-criteria-{CRITERION-id}-levels-addlevel', 'value' => $value, 'title' => $value)); $criterion_template .= html_writer::tag('td', $button, array('class' => 'addlevel')); } - if (isset($value['remark'])) { - $currentremark = $value['remark']; - } else { + $displayremark = ($options['enableremarks'] && ($mode != gradingform_rubric_controller::DISPLAY_VIEW || $options['showremarksstudent'])); + if ($displayremark) { $currentremark = ''; - } - if ($mode == gradingform_rubric_controller::DISPLAY_EVAL) { - $input = html_writer::tag('textarea', htmlspecialchars($currentremark), array('name' => '{NAME}[criteria][{CRITERION-id}][remark]', 'cols' => '10', 'rows' => '5')); - $criterion_template .= html_writer::tag('td', $input, array('class' => 'remark')); - } - if ($mode == gradingform_rubric_controller::DISPLAY_EVAL_FROZEN) { - $criterion_template .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => '{NAME}[criteria][{CRITERION-id}][remark]', 'value' => $currentremark)); - } - if ($mode == gradingform_rubric_controller::DISPLAY_REVIEW) { - $criterion_template .= html_writer::tag('td', $currentremark, array('class' => 'remark')); // TODO maybe some prefix here like 'Teacher remark:' + if (isset($value['remark'])) { + $currentremark = $value['remark']; + } + if ($mode == gradingform_rubric_controller::DISPLAY_EVAL) { + $input = html_writer::tag('textarea', htmlspecialchars($currentremark), array('name' => '{NAME}[criteria][{CRITERION-id}][remark]', 'cols' => '10', 'rows' => '5')); + $criterion_template .= html_writer::tag('td', $input, array('class' => 'remark')); + } else if ($mode == gradingform_rubric_controller::DISPLAY_EVAL_FROZEN) { + $criterion_template .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => '{NAME}[criteria][{CRITERION-id}][remark]', 'value' => $currentremark)); + }else if ($mode == gradingform_rubric_controller::DISPLAY_REVIEW || $mode == gradingform_rubric_controller::DISPLAY_VIEW) { + $criterion_template .= html_writer::tag('td', $currentremark, array('class' => 'remark')); // TODO maybe some prefix here like 'Teacher remark:' + } } $criterion_template .= html_writer::end_tag('tr'); // .criterion @@ -134,7 +134,7 @@ class gradingform_rubric_renderer { * @param array|null $level level data, also in view mode it might also have property $level['checked'] whether this level is checked * @return string */ - public function level_template($mode, $elementname = '{NAME}', $criterionid = '{CRITERION-id}', $level = null) { + public function level_template($mode, $options, $elementname = '{NAME}', $criterionid = '{CRITERION-id}', $level = null) { // TODO definition format if (!isset($level['id'])) { $level = array('id' => '{LEVEL-id}', 'definition' => '{LEVEL-definition}', 'score' => '{LEVEL-score}', 'class' => '{LEVEL-class}', 'checked' => false); @@ -148,14 +148,19 @@ class gradingform_rubric_renderer { } // Template for one level within one criterion - $level_template = html_writer::start_tag('td', array('id' => '{NAME}-{CRITERION-id}-levels-{LEVEL-id}', 'class' => 'clearfix level'. $level['class'])); + $tdattributes = array('id' => '{NAME}-criteria-{CRITERION-id}-levels-{LEVEL-id}', 'class' => 'level'. $level['class']); + if (isset($level['tdwidth'])) { + $tdattributes['width'] = round($level['tdwidth']).'%'; + } + $level_template = html_writer::start_tag('td', $tdattributes); + $level_template .= html_writer::start_tag('div', array('class' => 'level-wrapper')); if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FULL) { - $definition = html_writer::tag('textarea', htmlspecialchars($level['definition']), array('name' => '{NAME}[{CRITERION-id}][levels][{LEVEL-id}][definition]', 'cols' => '10', 'rows' => '4')); - $score = html_writer::empty_tag('input', array('type' => 'text', 'name' => '{NAME}[{CRITERION-id}][levels][{LEVEL-id}][score]', 'size' => '4', 'value' => $level['score'])); + $definition = html_writer::tag('textarea', htmlspecialchars($level['definition']), array('name' => '{NAME}[criteria][{CRITERION-id}][levels][{LEVEL-id}][definition]', 'cols' => '10', 'rows' => '4')); + $score = html_writer::empty_tag('input', array('type' => 'text', 'name' => '{NAME}[criteria][{CRITERION-id}][levels][{LEVEL-id}][score]', 'size' => '4', 'value' => $level['score'])); } else { if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FROZEN) { - $level_template .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => '{NAME}[{CRITERION-id}][levels][{LEVEL-id}][definition]', 'value' => $level['definition'])); - $level_template .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => '{NAME}[{CRITERION-id}][levels][{LEVEL-id}][score]', 'value' => $level['score'])); + $level_template .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => '{NAME}[criteria][{CRITERION-id}][levels][{LEVEL-id}][definition]', 'value' => $level['definition'])); + $level_template .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => '{NAME}[criteria][{CRITERION-id}][levels][{LEVEL-id}][score]', 'value' => $level['score'])); } $definition = $level['definition']; $score = $level['score']; @@ -168,14 +173,24 @@ class gradingform_rubric_renderer { if ($mode == gradingform_rubric_controller::DISPLAY_EVAL_FROZEN && $level['checked']) { $level_template .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => '{NAME}[criteria][{CRITERION-id}][levelid]', 'value' => $level['id'])); } - $score = html_writer::tag('span', $score, array('id' => '{NAME}-{CRITERION-id}-levels-{LEVEL-id}-score')); - $level_template .= html_writer::tag('div', $definition, array('class' => 'definition', 'id' => '{NAME}-{CRITERION-id}-levels-{LEVEL-id}-definition')); - $level_template .= html_writer::tag('div', $score. get_string('scorepostfix', 'gradingform_rubric'), array('class' => 'score')); + $score = html_writer::tag('span', $score, array('id' => '{NAME}-criteria-{CRITERION-id}-levels-{LEVEL-id}-score')); + $level_template .= html_writer::tag('div', $definition, array('class' => 'definition', 'id' => '{NAME}-criteria-{CRITERION-id}-levels-{LEVEL-id}-definition')); + $displayscore = true; + if (!$options['showscoreteacher'] && in_array($mode, array(gradingform_rubric_controller::DISPLAY_EVAL, gradingform_rubric_controller::DISPLAY_EVAL_FROZEN, gradingform_rubric_controller::DISPLAY_REVIEW))) { + $displayscore = false; + } + if (!$options['showscorestudent'] && $mode == gradingform_rubric_controller::DISPLAY_VIEW) { + $displayscore = false; + } + if ($displayscore) { + $level_template .= html_writer::tag('div', $score. get_string('scorepostfix', 'gradingform_rubric'), array('class' => 'score')); + } if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FULL) { $value = get_string('leveldelete', 'gradingform_rubric'); - $button = html_writer::empty_tag('input', array('type' => 'submit', 'name' => '{NAME}[{CRITERION-id}][levels][{LEVEL-id}][delete]', 'id' => '{NAME}-{CRITERION-id}-levels-{LEVEL-id}-delete', 'value' => $value, 'title' => $value)); + $button = html_writer::empty_tag('input', array('type' => 'submit', 'name' => '{NAME}[criteria][{CRITERION-id}][levels][{LEVEL-id}][delete]', 'id' => '{NAME}-criteria-{CRITERION-id}-levels-{LEVEL-id}-delete', 'value' => $value, 'title' => $value)); $level_template .= html_writer::tag('div', $button, array('class' => 'delete')); } + $level_template .= html_writer::end_tag('div'); // .level-wrapper $level_template .= html_writer::end_tag('td'); // .level $level_template = str_replace('{NAME}', $elementname, $level_template); @@ -202,7 +217,7 @@ class gradingform_rubric_renderer { * @param string $criteria_str evaluated templates for this rubric's criteria * @return string */ - protected function rubric_template($mode, $elementname, $criteria_str) { + protected function rubric_template($mode, $options, $elementname, $criteria_str) { $classsuffix = ''; // CSS suffix for class of the main div. Depends on the mode switch ($mode) { case gradingform_rubric_controller::DISPLAY_EDIT_FULL: @@ -217,20 +232,77 @@ class gradingform_rubric_renderer { $classsuffix = ' evaluate frozen'; break; case gradingform_rubric_controller::DISPLAY_REVIEW: $classsuffix = ' review'; break; + case gradingform_rubric_controller::DISPLAY_VIEW: + $classsuffix = ' view'; break; } $rubric_template = html_writer::start_tag('div', array('id' => 'rubric-{NAME}', 'class' => 'clearfix gradingform_rubric'.$classsuffix)); $rubric_template .= html_writer::tag('table', $criteria_str, array('class' => 'criteria', 'id' => '{NAME}-criteria')); if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FULL) { $value = get_string('addcriterion', 'gradingform_rubric'); - $input = html_writer::empty_tag('input', array('type' => 'submit', 'name' => '{NAME}[addcriterion]', 'id' => '{NAME}-addcriterion', 'value' => $value, 'title' => $value)); + $input = html_writer::empty_tag('input', array('type' => 'submit', 'name' => '{NAME}[criteria][addcriterion]', 'id' => '{NAME}-criteria-addcriterion', 'value' => $value, 'title' => $value)); $rubric_template .= html_writer::tag('div', $input, array('class' => 'addcriterion')); } + $rubric_template .= $this->rubric_edit_options($mode, $options); $rubric_template .= html_writer::end_tag('div'); return str_replace('{NAME}', $elementname, $rubric_template); } + protected function rubric_edit_options($mode, $options) { + if ($mode != gradingform_rubric_controller::DISPLAY_EDIT_FULL + && $mode != gradingform_rubric_controller::DISPLAY_EDIT_FROZEN + && $mode != gradingform_rubric_controller::DISPLAY_PREVIEW) { + // Options are displayed only in edit mode + return; + } + $html = html_writer::start_tag('div', array('class' => 'options')); + $html .= html_writer::tag('div', get_string('rubricoptions', 'gradingform_rubric'), array('class' => 'optionsheading')); + $attrs = array('type' => 'hidden', 'name' => '{NAME}[options][optionsset]', 'value' => 1); + 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_rubric'), array('class' => 'label')); + $value = (int)(!!$value); // make sure $value is either 0 or 1 + if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FULL) { + $selectoptions = array(0 => get_string($option.'0', 'gradingform_rubric'), 1 => get_string($option.'1', 'gradingform_rubric')); + $value_str = html_writer::select($selectoptions, $attrs['name'], $value, false, array('id' => $attrs['id'])); + $html .= html_writer::tag('span', $value_str, array('class' => 'value')); + // TODO add here button 'Sort levels' + } else { + $html .= html_writer::tag('span', get_string($option.$value, 'gradingform_rubric'), array('class' => 'value')); + if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FROZEN) { + $html .= html_writer::empty_tag('input', $attrs + array('type' => 'hidden', 'value' => $value)); + } + } + break; + default: + // Display option as checkbox + $attrs['type'] = 'checkbox'; + $attrs['value'] = 1; + if ($value) { + $attrs['checked'] = 'checked'; + } + if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FROZEN) { + $attrs['disabled'] = 'disabled'; + } + if ($mode == gradingform_rubric_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_rubric'), 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 rubric. Depending on $mode it may be the code * to edit rubric, to preview the rubric, to evaluate somebody or to review the evaluation. @@ -246,11 +318,12 @@ class gradingform_rubric_renderer { * @param array $values evaluation result * @return string */ - public function display_rubric($criteria, $mode, $elementname = null, $values = null) { + public function display_rubric($criteria, $options, $mode, $elementname = null, $values = null) { $criteria_str = ''; $cnt = 0; foreach ($criteria as $id => $criterion) { $criterion['class'] = $this->get_css_class_suffix($cnt++, sizeof($criteria) -1); + $criterion['id'] = $id; $levels_str = ''; $levelcnt = 0; if (isset($values['criteria'][$id])) { @@ -259,18 +332,20 @@ class gradingform_rubric_renderer { $criterionvalue = null; } foreach ($criterion['levels'] as $levelid => $level) { + $level['id'] = $levelid; $level['score'] = (float)$level['score']; // otherwise the display will look like 1.00000 $level['class'] = $this->get_css_class_suffix($levelcnt++, sizeof($criterion['levels']) -1); $level['checked'] = (isset($criterionvalue['levelid']) && ((int)$criterionvalue['levelid'] === $levelid)); - if ($level['checked'] && ($mode == gradingform_rubric_controller::DISPLAY_EVAL_FROZEN || $mode == gradingform_rubric_controller::DISPLAY_REVIEW)) { + if ($level['checked'] && ($mode == gradingform_rubric_controller::DISPLAY_EVAL_FROZEN || $mode == gradingform_rubric_controller::DISPLAY_REVIEW || $mode == gradingform_rubric_controller::DISPLAY_VIEW)) { $level['class'] .= ' checked'; //in mode DISPLAY_EVAL the class 'checked' will be added by JS if it is enabled. If JS is not enabled, the 'checked' class will only confuse } - $levels_str .= $this->level_template($mode, $elementname, $id, $level); + $level['tdwidth'] = 100/count($criterion['levels']); + $levels_str .= $this->level_template($mode, $options, $elementname, $id, $level); } - $criteria_str .= $this->criterion_template($mode, $elementname, $criterion, $levels_str, $criterionvalue); + $criteria_str .= $this->criterion_template($mode, $options, $elementname, $criterion, $levels_str, $criterionvalue); } - return $this->rubric_template($mode, $elementname, $criteria_str); + return $this->rubric_template($mode, $options, $elementname, $criteria_str); } /** @@ -323,7 +398,9 @@ class gradingform_rubric_renderer { */ public function display_instance(gradingform_rubric_instance $instance, $idx) { $criteria = $instance->get_controller()->get_definition()->rubric_criteria; + $options = $instance->get_controller()->get_options(); $values = $instance->get_rubric_filling(); - return $this->display_rubric($criteria, gradingform_rubric_controller::DISPLAY_REVIEW, 'rubric'.$idx, $values); + // TODO mode should be DISPLAY_REVIEW if this user is a teacher + return $this->display_rubric($criteria, $options, gradingform_rubric_controller::DISPLAY_VIEW, 'rubric'.$idx, $values); } } diff --git a/grade/grading/form/rubric/rubriceditor.php b/grade/grading/form/rubric/rubriceditor.php index 1b403660976..5146149df1a 100644 --- a/grade/grading/form/rubric/rubriceditor.php +++ b/grade/grading/form/rubric/rubriceditor.php @@ -50,6 +50,7 @@ class MoodleQuickForm_rubriceditor extends HTML_QuickForm_input { global $PAGE; $html = $this->_getTabs(); $renderer = $PAGE->get_renderer('gradingform_rubric'); + $data = $this->prepare_non_js_data(); if (!$this->_flagFrozen) { $mode = gradingform_rubric_controller::DISPLAY_EDIT_FULL; $module = array('name'=>'gradingform_rubriceditor', 'fullpath'=>'/grade/grading/form/rubric/js/rubriceditor.js', @@ -58,32 +59,54 @@ class MoodleQuickForm_rubriceditor extends HTML_QuickForm_input { )); $PAGE->requires->js_init_call('M.gradingform_rubriceditor.init', array( array('name' => $this->getName(), - 'criteriontemplate' => $renderer->criterion_template($mode, $this->getName()), - 'leveltemplate' => $renderer->level_template($mode, $this->getName()) + 'criteriontemplate' => $renderer->criterion_template($mode, $data['options'], $this->getName()), + 'leveltemplate' => $renderer->level_template($mode, $data['options'], $this->getName()) )), true, $module); } else { + // Rubric is frozen, no javascript needed if ($this->_persistantFreeze) { $mode = gradingform_rubric_controller::DISPLAY_EDIT_FROZEN; } else { $mode = gradingform_rubric_controller::DISPLAY_PREVIEW; } } - $html .= $renderer->display_rubric($this->prepare_non_js_data(), $mode, $this->getName()); + $html .= $renderer->display_rubric($data['criteria'], $data['options'], $mode, $this->getName()); return $html; } - function prepare_non_js_data() { - $return = array(); - $criteria = $this->getValue(); - if (empty($criteria)) { - $criteria = array(); + /** + * Prepares the data passed in $_POST: + * - processes the pressed buttons 'addlevel', 'addcriterion', 'moveup', 'movedown', 'delete' (when JavaScript is disabled) + * - if options not passed (i.e. we create a new rubric) fills the options array with the default values + * - if options are passed completes the options array with unchecked checkboxes + * + * @param array $value + * @return array + */ + function prepare_non_js_data($value = null) { + if (null === $value) { + $value = $this->getValue(); + } + $return = array('criteria' => array(), 'options' => gradingform_rubric_controller::get_default_options()); + if (!isset($value['criteria'])) { + $value['criteria'] = array(); + } + if (!empty($value['options'])) { + foreach (array_keys($return['options']) as $option) { + // special treatment for checkboxes + if (!empty($value['options'][$option])) { + $return['options'][$option] = $value['options'][$option]; + } else { + $return['options'][$option] = null; + } + } } $lastaction = null; $lastid = null; - foreach ($criteria as $id => $criterion) { + foreach ($value['criteria'] as $id => $criterion) { if ($id == 'addcriterion') { - $id = $this->get_next_id(array_keys($criteria)); + $id = $this->get_next_id(array_keys($value['criteria'])); $criterion = array('description' => ''); } $levels = array(); @@ -105,12 +128,12 @@ class MoodleQuickForm_rubriceditor extends HTML_QuickForm_input { if (array_key_exists('moveup', $criterion) || $lastaction == 'movedown') { unset($criterion['moveup']); if ($lastid !== null) { - $lastcriterion = $return[$lastid]; - unset($return[$lastid]); - $return[$id] = $criterion; - $return[$lastid] = $lastcriterion; + $lastcriterion = $return['criteria'][$lastid]; + unset($return['criteria'][$lastid]); + $return['criteria'][$id] = $criterion; + $return['criteria'][$lastid] = $lastcriterion; } else { - $return[$id] = $criterion; + $return['criteria'][$id] = $criterion; } $lastaction = null; $lastid = $id; @@ -120,13 +143,13 @@ class MoodleQuickForm_rubriceditor extends HTML_QuickForm_input { unset($criterion['movedown']); $lastaction = 'movedown'; } - $return[$id] = $criterion; + $return['criteria'][$id] = $criterion; $lastid = $id; } } $csortorder = 1; - foreach (array_keys($return) as $id) { - $return[$id]['sortorder'] = $csortorder++; + foreach (array_keys($return['criteria']) as $id) { + $return['criteria'][$id]['sortorder'] = $csortorder++; } return $return; } @@ -143,8 +166,8 @@ class MoodleQuickForm_rubriceditor extends HTML_QuickForm_input { function _ruleIsCompleted($elementValue) { //echo "_ruleIsCompleted"; - if (is_array($elementValue)) { - foreach ($elementValue as $criterionid => $criterion) { + if (isset($elementValue['criteria'])) { + foreach ($elementValue['criteria'] as $criterionid => $criterion) { if ($criterionid == 'addcriterion') { return false; } @@ -177,4 +200,16 @@ class MoodleQuickForm_rubriceditor extends HTML_QuickForm_input { return parent::onQuickFormEvent($event, $arg, $caller); } + /** + * Prepares the data for saving + * @see prepare_non_js_data + * + * @param array $submitValues + * @param boolean $assoc + * @return array + */ + function exportValue(&$submitValues, $assoc = false) { + $value = $this->prepare_non_js_data($this->_findValue($submitValues)); + return $this->_prepareValue($value, $assoc); + } } \ No newline at end of file diff --git a/grade/grading/form/rubric/styles.css b/grade/grading/form/rubric/styles.css index 4b3e64adafb..66dc3c01a09 100644 --- a/grade/grading/form/rubric/styles.css +++ b/grade/grading/form/rubric/styles.css @@ -1,5 +1,6 @@ /* .gradingform_rubric.editor[.frozen|.editable] + .criteria .criterion[.first][.last][.odd|.even] .controls .moveup @@ -10,31 +11,37 @@ [input type=submit] .description .levels - .level[.first][.last][.odd|.even] - .definition - [textarea] - .score - span - [input type=text] - .delete - [input type=submit] + td.level[.first][.last][.odd|.even] + div.level-wrapper + .definition + [textarea] + .score + span + [input type=text] + .delete + [input type=submit] .addlevel [input type=submit] .remark textarea .addcriterion [input type=submit] + .options + .optionsheading + .option.OPTIONNAME .gradingform_rubric[.review][.evaluate[.editable|.frozen]] + .criteria .criterion[.first][.last][.odd|.even] .description .levels - .level[.first][.last][.odd|.even] - .radio - input - .definition - .score - span + td.level[.first][.last][.odd|.even] + div.level-wrapper + div.radio + input + .definition + .score + span */ @@ -61,13 +68,14 @@ .gradingform_rubric .criterion .levels, .gradingform_rubric .criterion .levels table, .gradingform_rubric .criterion .levels table tbody {padding:0;margin:0;} -.gradingform_rubric .criterion .levels .level {border-left:1px solid #DDD;max-width:150px;position:relative;} +.gradingform_rubric .criterion .levels .level {border-left:1px solid #DDD;max-width:150px;} +.gradingform_rubric .criterion .levels .level .level-wrapper {position:relative;} .gradingform_rubric .criterion .levels .level.last {border-right:1px solid #DDD;} .gradingform_rubric .plainvalue.empty {font-style: italic; color: #AAA;} -.gradingform_rubric.editor .criterion .levels .level .delete {position:absolute;right:0px;bottom:0px;} -.gradingform_rubric .criterion .levels .level .score {display:block;} +.gradingform_rubric.editor .criterion .levels .level .delete {position:absolute;right:0;bottom:0;} +.gradingform_rubric .criterion .levels .level .score {font-style:italic;color:#575;font-weight: bold;margin-top:5px;} /* Make invisible the buttons 'Move up' for the first criterion and 'Move down' for the last, because those buttons will make no change */ .gradingform_rubric.editor .criterion.first .controls .moveup input, @@ -90,3 +98,8 @@ .gradingform_rubric.editor .addlevel input {background: transparent url([[pix:t/addgreen]]) no-repeat;display:block;color:#555555;font-weight:bold;text-decoration:none;} .gradingform_rubric.editor .addcriterion input {background-position: 5px 8px;height:30px;line-height:29px;margin-bottom:14px;padding-left:20px;padding-right:10px;} .gradingform_rubric.editor .addlevel input {background-position: 5px 6px;height:25px;line-height:24px;margin-bottom:10px;padding-left:18px;padding-right:8px;} + +.gradingform_rubric .options .optionsheading {font-weight:bold;font-size:1.1em;padding-bottom:5px;} +.gradingform_rubric .options .option {padding-bottom:2px;} +.gradingform_rubric .options .option label {margin-left: 5px;} +.gradingform_rubric .options .option .value {margin-left: 5px;font-weight:bold;}