Merge pull request #17 from marinaglancy/wip-rubricrenderer-rubric

Better rendering of the rubrics, rubric display options
This commit is contained in:
David Mudrak 2011-10-26 23:47:29 -07:00
commit 72e48ad28f
7 changed files with 418 additions and 176 deletions

View file

@ -57,9 +57,9 @@ class gradingform_rubric_editrubric extends moodleform {
$form->setType('description_editor', PARAM_RAW); $form->setType('description_editor', PARAM_RAW);
// rubric editor // rubric editor
$element = $form->addElement('rubriceditor', 'rubric_criteria', 'Rubric 1'); // todo label $element = $form->addElement('rubriceditor', 'rubric', get_string('rubric', 'gradingform_rubric'));
$form->setType('rubric_criteria', PARAM_RAW); $form->setType('rubric', PARAM_RAW);
$form->addRule('rubric_criteria', '', 'rubriceditorcompleted'); //TODO how to add this rule automatically????? $form->addRule('rubric', '', 'rubriceditorcompleted'); //TODO how to add this rule automatically?????
if (array_key_exists('freezerubric', $this->_customdata) && $this->_customdata['freezerubric']) { if (array_key_exists('freezerubric', $this->_customdata) && $this->_customdata['freezerubric']) {
$element->freeze(); $element->freeze();
} }

View file

@ -92,10 +92,10 @@ M.gradingform_rubriceditor.buttonclick = function(e, Y, name, confirmed) {
if (e.target.get('type') != 'submit') return; if (e.target.get('type') != 'submit') return;
var chunks = e.target.get('id').split('-'), var chunks = e.target.get('id').split('-'),
action = chunks[chunks.length-1] action = chunks[chunks.length-1]
if (chunks[0] != name) return; if (chunks[0] != name || chunks[1] != 'criteria') return;
var elements_str var elements_str
if (chunks.length>3 || action == 'addlevel') { if (chunks.length>4 || action == 'addlevel') {
elements_str = '#rubric-'+name+' #'+name+'-'+chunks[1]+'-levels .level' elements_str = '#rubric-'+name+' #'+name+'-criteria-'+chunks[2]+'-levels .level'
} else { } else {
elements_str = '#rubric-'+name+' .criterion' elements_str = '#rubric-'+name+' .criterion'
} }
@ -112,38 +112,44 @@ M.gradingform_rubriceditor.buttonclick = function(e, Y, name, confirmed) {
'callbackargs' : [e, Y, name, true], 'callbackargs' : [e, Y, name, true],
'callback' : M.gradingform_rubriceditor.buttonclick 'callback' : M.gradingform_rubriceditor.buttonclick
}; };
if (chunks.length == 2 && action == 'addcriterion') { if (chunks.length == 3 && action == 'addcriterion') {
// ADD NEW CRITERION // ADD NEW CRITERION
var newcriterion = M.gradingform_rubriceditor.templates[name]['criterion']. var newcriterion = M.gradingform_rubriceditor.templates[name]['criterion'].
replace(/\{CRITERION-id\}/g, 'NEWID'+newid).replace(/\{.+?\}/g, '') 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); M.gradingform_rubriceditor.addhandlers(Y, name);
} else if (chunks.length == 4 && action == 'addlevel') { } else if (chunks.length == 5 && action == 'addlevel') {
// ADD NEW LEVEL // ADD NEW LEVEL
var newlevel = M.gradingform_rubriceditor.templates[name]['level']. var newlevel = M.gradingform_rubriceditor.templates[name]['level'].
replace(/\{CRITERION-id\}/g, chunks[1]).replace(/\{LEVEL-id\}/g, 'NEWID'+newid).replace(/\{.+?\}/g, '') replace(/\{CRITERION-id\}/g, chunks[2]).replace(/\{LEVEL-id\}/g, 'NEWID'+newid).replace(/\{.+?\}/g, '')
Y.one('#'+name+'-'+chunks[1]+'-levels').append(newlevel) 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); M.gradingform_rubriceditor.addhandlers(Y, name);
} else if (chunks.length == 3 && action == 'moveup') { } else if (chunks.length == 4 && action == 'moveup') {
// MOVE CRITERION UP // 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()) 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 // 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) 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 // DELETE CRITERION
if (confirmed) { if (confirmed) {
Y.one('#'+name+'-'+chunks[1]).remove() Y.one('#'+name+'-criteria-'+chunks[2]).remove()
} else { } else {
dialog_options['message'] = M.str.gradingform_rubric.confirmdeletecriterion dialog_options['message'] = M.str.gradingform_rubric.confirmdeletecriterion
M.util.show_confirm_dialog(e, dialog_options); M.util.show_confirm_dialog(e, dialog_options);
} }
} else if (chunks.length == 5 && action == 'delete') { } else if (chunks.length == 6 && action == 'delete') {
// DELETE LEVEL // DELETE LEVEL
if (confirmed) { 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 { } else {
dialog_options['message'] = M.str.gradingform_rubric.confirmdeletelevel dialog_options['message'] = M.str.gradingform_rubric.confirmdeletelevel
M.util.show_confirm_dialog(e, dialog_options); M.util.show_confirm_dialog(e, dialog_options);

View file

@ -37,8 +37,21 @@ $string['criterionmoveup'] = 'Move up';
$string['criteriondelete'] = 'Delete criterion'; $string['criteriondelete'] = 'Delete criterion';
$string['criterionmovedown'] = 'Move down'; $string['criterionmovedown'] = 'Move down';
$string['criterionaddlevel'] = 'Add level'; $string['criterionaddlevel'] = 'Add level';
$string['scorepostfix'] = ' pts'; $string['scorepostfix'] = ' points';
$string['leveldelete'] = 'Delete level'; $string['leveldelete'] = 'Delete level';
$string['criterionempty'] = 'Click to edit criterion'; $string['criterionempty'] = 'Click to edit criterion';
$string['levelempty'] = 'Click to edit level'; $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';

View file

@ -38,7 +38,8 @@ class gradingform_rubric_controller extends gradingform_controller {
const DISPLAY_PREVIEW = 3; // Preview the rubric design const DISPLAY_PREVIEW = 3; // Preview the rubric design
const DISPLAY_EVAL = 4; // For evaluation, enabled (teacher grades a student) const DISPLAY_EVAL = 4; // For evaluation, enabled (teacher grades a student)
const DISPLAY_EVAL_FROZEN = 5; // For evaluation, with hidden fields 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 * 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::update_definition((object)array('descriptionformat' => FORMAT_MOODLE), $usermodified);
parent::load_definition(); parent::load_definition();
} }
$options = self::description_form_field_options($this->get_context()); if (!isset($newdefinition->rubric['options'])) {
$newdefinition = file_postupdate_standard_editor($newdefinition, 'description', $options, $this->get_context(), $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); 'gradingform_rubric', 'definition_description', $this->definition->id);
parent::update_definition($newdefinition, $usermodified); parent::update_definition($newdefinition, $usermodified);
@ -83,10 +88,10 @@ class gradingform_rubric_controller extends gradingform_controller {
// update rubric data // update rubric data
$haschanges = false; $haschanges = false;
if (empty($newdefinition->rubric_criteria)) { if (empty($newdefinition->rubric['criteria'])) {
$newcriteria = array(); $newcriteria = array();
} else { } else {
$newcriteria = $newdefinition->rubric_criteria; // new ones to be saved $newcriteria = $newdefinition->rubric['criteria']; // new ones to be saved
} }
$currentcriteria = $currentdefinition->rubric_criteria; $currentcriteria = $currentdefinition->rubric_criteria;
$criteriafields = array('sortorder', 'description', 'descriptionformat'); $criteriafields = array('sortorder', 'description', 'descriptionformat');
@ -175,7 +180,6 @@ class gradingform_rubric_controller extends gradingform_controller {
*/ */
protected function load_definition() { protected function load_definition() {
global $DB; global $DB;
$sql = "SELECT gd.*, $sql = "SELECT gd.*,
rc.id AS rcid, rc.sortorder AS rcsortorder, rc.description AS rcdescription, rc.descriptionformat AS rcdescriptionformat, 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 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(); $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 = new stdClass();
$properties->areaid = $this->areaid; $properties->areaid = $this->areaid;
if ($definition) { 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; $properties->$key = $definition->$key;
} }
$options = self::description_form_field_options($this->get_context()); $options = self::description_form_field_options($this->get_context());
$properties = file_prepare_standard_editor($properties, 'description', $options, $this->get_context(), $properties = file_prepare_standard_editor($properties, 'description', $options, $this->get_context(),
'gradingform_rubric', 'definition_description', $definition->id); 'gradingform_rubric', 'definition_description', $definition->id);
} }
$properties->rubric = array('criteria' => array(), 'options' => $this->get_options());
if (!empty($definition->rubric_criteria)) { if (!empty($definition->rubric_criteria)) {
$properties->rubric_criteria = $definition->rubric_criteria; $properties->rubric['criteria'] = $definition->rubric_criteria;
} else {
$properties->rubric_criteria = array();
} }
return $properties; return $properties;
@ -252,11 +286,12 @@ class gradingform_rubric_controller extends gradingform_controller {
public function get_definition_copy(gradingform_controller $target) { public function get_definition_copy(gradingform_controller $target) {
$new = parent::get_definition_copy($target); $new = parent::get_definition_copy($target);
$old = $this->get_definition(); $old = $this->get_definition_for_editing();
$new->rubric_criteria = array(); $new->description_editor = $old->description_editor;
$new->rubric = array('criteria' => array(), 'options' => $old->rubric['options']);
$newcritid = 1; $newcritid = 1;
$newlevid = 1; $newlevid = 1;
foreach ($old->rubric_criteria as $oldcritid => $oldcrit) { foreach ($old->rubric['criteria'] as $oldcritid => $oldcrit) {
unset($oldcrit['id']); unset($oldcrit['id']);
if (isset($oldcrit['levels'])) { if (isset($oldcrit['levels'])) {
foreach ($oldcrit['levels'] as $oldlevid => $oldlev) { foreach ($oldcrit['levels'] as $oldlevid => $oldlev) {
@ -268,7 +303,7 @@ class gradingform_rubric_controller extends gradingform_controller {
} else { } else {
$oldcrit['levels'] = array(); $oldcrit['levels'] = array();
} }
$new->rubric_criteria['NEWID'.$newcritid] = $oldcrit; $new->rubric['criteria']['NEWID'.$newcritid] = $oldcrit;
$newcritid++; $newcritid++;
} }
@ -337,7 +372,8 @@ class gradingform_rubric_controller extends gradingform_controller {
// append the rubric itself, using own renderer // append the rubric itself, using own renderer
$output = $this->get_renderer($page); $output = $this->get_renderer($page);
$criteria = $this->definition->rubric_criteria; $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; return $header . $rubric;
} }
@ -556,10 +592,11 @@ class gradingform_rubric_instance extends gradingform_instance {
} }
} }
$criteria = $this->get_controller()->get_definition()->rubric_criteria; $criteria = $this->get_controller()->get_definition()->rubric_criteria;
$options = $this->get_controller()->get_options();
$value = $gradingformelement->getValue(); $value = $gradingformelement->getValue();
if ($value === null) { if ($value === null) {
$value = $this->get_rubric_filling(); $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);
} }
} }

View file

@ -22,7 +22,6 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/ */
defined('MOODLE_INTERNAL') || die(); defined('MOODLE_INTERNAL') || die();
/** /**
@ -31,11 +30,28 @@ defined('MOODLE_INTERNAL') || die();
class gradingform_rubric_renderer { class gradingform_rubric_renderer {
/** /**
* This function returns html code for displaying criterion. Depending on $mode it may be the
* code to edit rubric, to preview the rubric, to evaluate somebody or to review the evaluation.
* *
* @param int $mode @see gradingform_rubric_controller * This function may be called from display_rubric() to display the whole rubric, or it can be
* called by itself to return a template used by JavaScript to add new empty criteria to the
* rubric 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 rubric display mode @see gradingform_rubric_controller
* @param string $elementname the name of the form element (in editor mode) or the prefix for div ids (in view mode)
* @param array|null $criterion criterion data
* @param string $levels_str evaluated templates for this criterion levels
* @param array|null $value (only in view mode) teacher's feedback on this criterion
* @return string * @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 // TODO description format, remark format
if ($criterion === null || !is_array($criterion) || !array_key_exists('id', $criterion)) { 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}'); $criterion = array('id' => '{CRITERION-id}', 'description' => '{CRITERION-description}', 'sortorder' => '{CRITERION-sortorder}', 'class' => '{CRITERION-class}');
@ -47,56 +63,78 @@ class gradingform_rubric_renderer {
} }
} }
} }
$criterion_template = html_writer::start_tag('div', 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) { if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FULL) {
$criterion_template .= html_writer::start_tag('div', array('class' => 'controls')); $criterion_template .= html_writer::start_tag('td', array('class' => 'controls'));
foreach (array('moveup', 'delete', 'movedown') as $key) { foreach (array('moveup', 'delete', 'movedown') as $key) {
$value = get_string('criterion'.$key, 'gradingform_rubric'); $value = get_string('criterion'.$key, 'gradingform_rubric');
$button = html_writer::empty_tag('input', array('type' => 'submit', 'name' => '{NAME}[{CRITERION-id}]['.$key.']', $button = html_writer::empty_tag('input', array('type' => 'submit', 'name' => '{NAME}[criteria][{CRITERION-id}]['.$key.']',
'id' => '{NAME}-{CRITERION-id}-'.$key, 'value' => $value, 'title' => $value)); 'id' => '{NAME}-criteria-{CRITERION-id}-'.$key, 'value' => $value, 'title' => $value));
$criterion_template .= html_writer::tag('div', $button, array('class' => $key)); $criterion_template .= html_writer::tag('div', $button, array('class' => $key));
} }
$criterion_template .= html_writer::end_tag('div'); // .controls $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'])); $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}[{CRITERION-id}][description]', 'cols' => '10', 'rows' => '5')); $description = html_writer::tag('textarea', htmlspecialchars($criterion['description']), array('name' => '{NAME}[criteria][{CRITERION-id}][description]', 'cols' => '10', 'rows' => '5'));
} else { } else {
if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FROZEN) { 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}[criteria][{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}][description]', 'value' => $criterion['description']));
} }
$description = $criterion['description']; $description = $criterion['description'];
} }
$criterion_template .= html_writer::tag('div', $description, array('class' => 'description', 'id' => '{NAME}-{CRITERION-id}-description')); $criterion_template .= html_writer::tag('td', $description, array('class' => 'description', 'id' => '{NAME}-criteria-{CRITERION-id}-description'));
$criterion_template .= html_writer::tag('div', $levels_str, array('class' => 'clearfix levels', 'id' => '{NAME}-{CRITERION-id}-levels')); $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) { if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FULL) {
$value = get_string('criterionaddlevel', 'gradingform_rubric'); $value = get_string('criterionaddlevel', 'gradingform_rubric');
$button = html_writer::empty_tag('input', array('type' => 'submit', 'name' => '{NAME}[{CRITERION-id}][levels][addlevel]', $button = html_writer::empty_tag('input', array('type' => 'submit', 'name' => '{NAME}[criteria][{CRITERION-id}][levels][addlevel]',
'id' => '{NAME}-{CRITERION-id}-levels-addlevel', 'value' => $value, 'title' => $value)); //TODO '{NAME}-{CRITERION-id}-levels-addlevel 'id' => '{NAME}-criteria-{CRITERION-id}-levels-addlevel', 'value' => $value, 'title' => $value));
$criterion_template .= html_writer::tag('div', $button, array('class' => 'addlevel')); $criterion_template .= html_writer::tag('td', $button, array('class' => 'addlevel'));
} }
if (isset($value['remark'])) { $displayremark = ($options['enableremarks'] && ($mode != gradingform_rubric_controller::DISPLAY_VIEW || $options['showremarksstudent']));
$currentremark = $value['remark']; if ($displayremark) {
} else {
$currentremark = ''; $currentremark = '';
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:'
}
} }
if ($mode == gradingform_rubric_controller::DISPLAY_EVAL) { $criterion_template .= html_writer::end_tag('tr'); // .criterion
$input = html_writer::tag('textarea', htmlspecialchars($currentremark), array('name' => '{NAME}[criteria][{CRITERION-id}][remark]', 'cols' => '10', 'rows' => '5'));
$criterion_template .= html_writer::tag('div', $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('div', $currentremark, array('class' => 'remark')); // TODO maybe some prefix here like 'Teacher remark:'
}
$criterion_template .= html_writer::end_tag('div'); // .criterion
$criterion_template = str_replace('{NAME}', $elementname, $criterion_template); $criterion_template = str_replace('{NAME}', $elementname, $criterion_template);
$criterion_template = str_replace('{CRITERION-id}', $criterion['id'], $criterion_template); $criterion_template = str_replace('{CRITERION-id}', $criterion['id'], $criterion_template);
return $criterion_template; return $criterion_template;
} }
public function level_template($mode, $elementname = '{NAME}', $criterionid = '{CRITERION-id}', $level = null) { /**
* This function returns html code for displaying one level of one criterion. Depending on $mode
* it may be the code to edit rubric, to preview the rubric, to evaluate somebody or to review the evaluation.
*
* This function may be called from display_rubric() to display the whole rubric, or it can be
* called by itself to return a template used by JavaScript to add new empty level to the
* criterion during the design of rubric.
* In this case it will use macros like {NAME}, {CRITERION-id}, {LEVEL-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 rubric display mode @see gradingform_rubric_controller
* @param string $elementname the name of the form element (in editor mode) or the prefix for div ids (in view mode)
* @param string|int $criterionid either id of the nesting criterion or a macro for template
* @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, $options, $elementname = '{NAME}', $criterionid = '{CRITERION-id}', $level = null) {
// TODO definition format // TODO definition format
if (!isset($level['id'])) { if (!isset($level['id'])) {
$level = array('id' => '{LEVEL-id}', 'definition' => '{LEVEL-definition}', 'score' => '{LEVEL-score}', 'class' => '{LEVEL-class}', 'checked' => false); $level = array('id' => '{LEVEL-id}', 'definition' => '{LEVEL-definition}', 'score' => '{LEVEL-score}', 'class' => '{LEVEL-class}', 'checked' => false);
@ -110,14 +148,19 @@ class gradingform_rubric_renderer {
} }
// Template for one level within one criterion // Template for one level within one criterion
$level_template = html_writer::start_tag('div', 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) { 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')); $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}[{CRITERION-id}][levels][{LEVEL-id}][score]', 'size' => '4', 'value' => $level['score'])); $score = html_writer::empty_tag('input', array('type' => 'text', 'name' => '{NAME}[criteria][{CRITERION-id}][levels][{LEVEL-id}][score]', 'size' => '4', 'value' => $level['score']));
} else { } else {
if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FROZEN) { 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}[criteria][{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}][score]', 'value' => $level['score']));
} }
$definition = $level['definition']; $definition = $level['definition'];
$score = $level['score']; $score = $level['score'];
@ -130,15 +173,25 @@ class gradingform_rubric_renderer {
if ($mode == gradingform_rubric_controller::DISPLAY_EVAL_FROZEN && $level['checked']) { 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'])); $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')); $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}-{CRITERION-id}-levels-{LEVEL-id}-definition')); $level_template .= html_writer::tag('div', $definition, array('class' => 'definition', 'id' => '{NAME}-criteria-{CRITERION-id}-levels-{LEVEL-id}-definition'));
$level_template .= html_writer::tag('div', $score. get_string('scorepostfix', 'gradingform_rubric'), array('class' => 'score')); $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) { if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FULL) {
$value = get_string('leveldelete', 'gradingform_rubric'); $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::tag('div', $button, array('class' => 'delete'));
} }
$level_template .= html_writer::end_tag('div'); // .level $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); $level_template = str_replace('{NAME}', $elementname, $level_template);
$level_template = str_replace('{CRITERION-id}', $criterionid, $level_template); $level_template = str_replace('{CRITERION-id}', $criterionid, $level_template);
@ -146,7 +199,25 @@ class gradingform_rubric_renderer {
return $level_template; return $level_template;
} }
protected function rubric_template($mode, $elementname = '{NAME}', $criteria_str = '{CRITERIA}') { /**
* This function returns html code for displaying rubric template (content before and after
* criteria list). Depending on $mode it may be the code to edit rubric, to preview the rubric,
* to evaluate somebody or to review the evaluation.
*
* This function is called from display_rubric() to display the whole rubric.
*
* 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 rubric display mode @see gradingform_rubric_controller
* @param string $elementname the name of the form element (in editor mode) or the prefix for div ids (in view mode)
* @param string $criteria_str evaluated templates for this rubric's criteria
* @return string
*/
protected function rubric_template($mode, $options, $elementname, $criteria_str) {
$classsuffix = ''; // CSS suffix for class of the main div. Depends on the mode $classsuffix = ''; // CSS suffix for class of the main div. Depends on the mode
switch ($mode) { switch ($mode) {
case gradingform_rubric_controller::DISPLAY_EDIT_FULL: case gradingform_rubric_controller::DISPLAY_EDIT_FULL:
@ -161,34 +232,98 @@ class gradingform_rubric_renderer {
$classsuffix = ' evaluate frozen'; break; $classsuffix = ' evaluate frozen'; break;
case gradingform_rubric_controller::DISPLAY_REVIEW: case gradingform_rubric_controller::DISPLAY_REVIEW:
$classsuffix = ' review'; break; $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 form_rubric'.$classsuffix)); $rubric_template = html_writer::start_tag('div', array('id' => 'rubric-{NAME}', 'class' => 'clearfix gradingform_rubric'.$classsuffix));
$rubric_template .= html_writer::tag('div', $criteria_str, array('class' => 'criteria', 'id' => '{NAME}-criteria')); $rubric_template .= html_writer::tag('table', $criteria_str, array('class' => 'criteria', 'id' => '{NAME}-criteria'));
if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FULL) { if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FULL) {
$value = get_string('addcriterion', 'gradingform_rubric'); $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 .= html_writer::tag('div', $input, array('class' => 'addcriterion'));
} }
$rubric_template .= $this->rubric_edit_options($mode, $options);
$rubric_template .= html_writer::end_tag('div'); $rubric_template .= html_writer::end_tag('div');
return str_replace('{NAME}', $elementname, $rubric_template); 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;
}
/** /**
* Returns html code for displaying the rubric in the specified mode * 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.
* *
* @param array $criteria * It is very unlikely that this function needs to be overriden by theme. It does not produce
* @param int $mode * any html code, it just prepares data about rubric design and evaluation, adds the CSS
* @param string $elementname * class to elements and calls the functions level_template, criterion_template and
* @param array $values * rubric_template
*
* @param array $criteria data about the rubric design
* @param int $mode rubric display mode @see gradingform_rubric_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
* @return string * @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 = ''; $criteria_str = '';
$cnt = 0; $cnt = 0;
foreach ($criteria as $id => $criterion) { foreach ($criteria as $id => $criterion) {
$criterion['class'] = $this->get_css_class_suffix($cnt++, sizeof($criteria) -1); $criterion['class'] = $this->get_css_class_suffix($cnt++, sizeof($criteria) -1);
$criterion['id'] = $id;
$levels_str = ''; $levels_str = '';
$levelcnt = 0; $levelcnt = 0;
if (isset($values['criteria'][$id])) { if (isset($values['criteria'][$id])) {
@ -197,28 +332,30 @@ class gradingform_rubric_renderer {
$criterionvalue = null; $criterionvalue = null;
} }
foreach ($criterion['levels'] as $levelid => $level) { foreach ($criterion['levels'] as $levelid => $level) {
$level['id'] = $levelid;
$level['score'] = (float)$level['score']; // otherwise the display will look like 1.00000 $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['class'] = $this->get_css_class_suffix($levelcnt++, sizeof($criterion['levels']) -1);
$level['checked'] = (isset($criterionvalue['levelid']) && ((int)$criterionvalue['levelid'] === $levelid)); $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'; $level['class'] .= ' checked';
//in mode DISPLAY_EVAL the class 'checked' will be added by JS if it is enabled. If it is not enabled, the 'checked' class will only confuse //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);
} }
/** /**
* Help function to return CSS class names for element (first/last/even/odd) * Help function to return CSS class names for element (first/last/even/odd) with leading space
* *
* @param <type> $cnt * @param int $cnt
* @param <type> $maxcnt * @param int $maxcnt
* @return string * @return string
*/ */
private function get_css_class_suffix($cnt, $maxcnt) { protected function get_css_class_suffix($cnt, $maxcnt) {
$class = ''; $class = '';
if ($cnt == 0) { if ($cnt == 0) {
$class .= ' first'; $class .= ' first';
@ -261,7 +398,9 @@ class gradingform_rubric_renderer {
*/ */
public function display_instance(gradingform_rubric_instance $instance, $idx) { public function display_instance(gradingform_rubric_instance $instance, $idx) {
$criteria = $instance->get_controller()->get_definition()->rubric_criteria; $criteria = $instance->get_controller()->get_definition()->rubric_criteria;
$options = $instance->get_controller()->get_options();
$values = $instance->get_rubric_filling(); $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);
} }
} }

View file

@ -50,6 +50,7 @@ class MoodleQuickForm_rubriceditor extends HTML_QuickForm_input {
global $PAGE; global $PAGE;
$html = $this->_getTabs(); $html = $this->_getTabs();
$renderer = $PAGE->get_renderer('gradingform_rubric'); $renderer = $PAGE->get_renderer('gradingform_rubric');
$data = $this->prepare_non_js_data();
if (!$this->_flagFrozen) { if (!$this->_flagFrozen) {
$mode = gradingform_rubric_controller::DISPLAY_EDIT_FULL; $mode = gradingform_rubric_controller::DISPLAY_EDIT_FULL;
$module = array('name'=>'gradingform_rubriceditor', 'fullpath'=>'/grade/grading/form/rubric/js/rubriceditor.js', $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( $PAGE->requires->js_init_call('M.gradingform_rubriceditor.init', array(
array('name' => $this->getName(), array('name' => $this->getName(),
'criteriontemplate' => $renderer->criterion_template($mode, $this->getName()), 'criteriontemplate' => $renderer->criterion_template($mode, $data['options'], $this->getName()),
'leveltemplate' => $renderer->level_template($mode, $this->getName()) 'leveltemplate' => $renderer->level_template($mode, $data['options'], $this->getName())
)), )),
true, $module); true, $module);
} else { } else {
// Rubric is frozen, no javascript needed
if ($this->_persistantFreeze) { if ($this->_persistantFreeze) {
$mode = gradingform_rubric_controller::DISPLAY_EDIT_FROZEN; $mode = gradingform_rubric_controller::DISPLAY_EDIT_FROZEN;
} else { } else {
$mode = gradingform_rubric_controller::DISPLAY_PREVIEW; $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; return $html;
} }
function prepare_non_js_data() { /**
$return = array(); * Prepares the data passed in $_POST:
$criteria = $this->getValue(); * - processes the pressed buttons 'addlevel', 'addcriterion', 'moveup', 'movedown', 'delete' (when JavaScript is disabled)
if (empty($criteria)) { * - if options not passed (i.e. we create a new rubric) fills the options array with the default values
$criteria = array(); * - 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; $lastaction = null;
$lastid = null; $lastid = null;
foreach ($criteria as $id => $criterion) { foreach ($value['criteria'] as $id => $criterion) {
if ($id == 'addcriterion') { if ($id == 'addcriterion') {
$id = $this->get_next_id(array_keys($criteria)); $id = $this->get_next_id(array_keys($value['criteria']));
$criterion = array('description' => ''); $criterion = array('description' => '');
} }
$levels = array(); $levels = array();
@ -105,12 +128,12 @@ class MoodleQuickForm_rubriceditor extends HTML_QuickForm_input {
if (array_key_exists('moveup', $criterion) || $lastaction == 'movedown') { if (array_key_exists('moveup', $criterion) || $lastaction == 'movedown') {
unset($criterion['moveup']); unset($criterion['moveup']);
if ($lastid !== null) { if ($lastid !== null) {
$lastcriterion = $return[$lastid]; $lastcriterion = $return['criteria'][$lastid];
unset($return[$lastid]); unset($return['criteria'][$lastid]);
$return[$id] = $criterion; $return['criteria'][$id] = $criterion;
$return[$lastid] = $lastcriterion; $return['criteria'][$lastid] = $lastcriterion;
} else { } else {
$return[$id] = $criterion; $return['criteria'][$id] = $criterion;
} }
$lastaction = null; $lastaction = null;
$lastid = $id; $lastid = $id;
@ -120,13 +143,13 @@ class MoodleQuickForm_rubriceditor extends HTML_QuickForm_input {
unset($criterion['movedown']); unset($criterion['movedown']);
$lastaction = 'movedown'; $lastaction = 'movedown';
} }
$return[$id] = $criterion; $return['criteria'][$id] = $criterion;
$lastid = $id; $lastid = $id;
} }
} }
$csortorder = 1; $csortorder = 1;
foreach (array_keys($return) as $id) { foreach (array_keys($return['criteria']) as $id) {
$return[$id]['sortorder'] = $csortorder++; $return['criteria'][$id]['sortorder'] = $csortorder++;
} }
return $return; return $return;
} }
@ -143,8 +166,8 @@ class MoodleQuickForm_rubriceditor extends HTML_QuickForm_input {
function _ruleIsCompleted($elementValue) { function _ruleIsCompleted($elementValue) {
//echo "_ruleIsCompleted"; //echo "_ruleIsCompleted";
if (is_array($elementValue)) { if (isset($elementValue['criteria'])) {
foreach ($elementValue as $criterionid => $criterion) { foreach ($elementValue['criteria'] as $criterionid => $criterion) {
if ($criterionid == 'addcriterion') { if ($criterionid == 'addcriterion') {
return false; return false;
} }
@ -177,4 +200,16 @@ class MoodleQuickForm_rubriceditor extends HTML_QuickForm_input {
return parent::onQuickFormEvent($event, $arg, $caller); 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);
}
} }

View file

@ -1,6 +1,7 @@
/* /*
.form_rubric.editor[.frozen|.editable] .gradingform_rubric.editor[.frozen|.editable]
.criterion[.first][.last].odd/even .criteria
.criterion[.first][.last][.odd|.even]
.controls .controls
.moveup .moveup
[input type=submit] [input type=submit]
@ -10,84 +11,95 @@
[input type=submit] [input type=submit]
.description .description
.levels .levels
.level[.first][.last].odd/even td.level[.first][.last][.odd|.even]
.definition div.level-wrapper
[textarea] .definition
.score [textarea]
span .score
[input type=text] span
.delete [input type=text]
[input type=submit] .delete
[input type=submit]
.addlevel .addlevel
[input type=submit] [input type=submit]
.remark .remark
textarea textarea
.addcriterion .addcriterion
[input type=submit] [input type=submit]
.options
.optionsheading
.option.OPTIONNAME
.form_rubric.evaluate .gradingform_rubric[.review][.evaluate[.editable|.frozen]]
.criterion[.first][.last].odd/even .criteria
.criterion[.first][.last][.odd|.even]
.description .description
.levels .levels
.level[.first][.last].odd/even td.level[.first][.last][.odd|.even]
.radio div.level-wrapper
input div.radio
.definition input
.score .definition
span .score
span
*/ */
.gradingform_rubric.editor .criterion .controls,
.gradingform_rubric .criterion .description,
.gradingform_rubric .criterion .levels,
.gradingform_rubric.editor .criterion .addlevel,
.gradingform_rubric .criterion .remark,
.gradingform_rubric .criterion .levels .level {vertical-align: top;}
.form_rubric.editor .criterion .controls, .gradingform_rubric.editor .criterion .controls,
.form_rubric .criterion .description, .gradingform_rubric .criterion .description,
.form_rubric .criterion .levels, .gradingform_rubric.editor .criterion .addlevel,
.form_rubric.editor .criterion .addlevel, .gradingform_rubric .criterion .remark,
.form_rubric .criterion .remark, .gradingform_rubric .criterion .levels .level {padding:3px;}
.form_rubric .criterion .levels .level {display: inline-block; vertical-align: top;overflow: hidden;}
.form_rubric.editor .criterion .controls, .gradingform_rubric .criteria {height:100%;}
.form_rubric .criterion .description, .gradingform_rubric .criterion {border:1px solid #DDD;overflow: hidden;}
.form_rubric.editor .criterion .addlevel, .gradingform_rubric .criterion.even {background:#F0F0F0;}
.form_rubric .criterion .remark,
.form_rubric .criterion .levels .level {padding:3px;}
/* Those divs should extend vertically and fill 100% of parent element height */ .gradingform_rubric .criterion .description {width:150px;font-weight:bold;}
.form_rubric .criterion .levels .level,
.form_rubric .criterion .description,
.form_rubric .criterion .levels {padding-bottom: 32767px;margin-bottom: -32767px;}
.form_rubric .criterion {border:1px solid #DDD;overflow: hidden;} .gradingform_rubric .criterion .levels table {width:100%;height:100%;}
.form_rubric .criterion.even {background:#F0F0F0;} .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;}
.gradingform_rubric .criterion .levels .level .level-wrapper {position:relative;}
.gradingform_rubric .criterion .levels .level.last {border-right:1px solid #DDD;}
.form_rubric .criterion .description {width:150px;font-weight:bold;} .gradingform_rubric .plainvalue.empty {font-style: italic; color: #AAA;}
.form_rubric .criterion .levels .level {border-left:1px solid #DDD;min-width:80px;max-width:150px;position:relative;} .gradingform_rubric.editor .criterion .levels .level .delete {position:absolute;right:0;bottom:0;}
.form_rubric .criterion .levels .level.last {border-right:1px solid #DDD;} .gradingform_rubric .criterion .levels .level .score {font-style:italic;color:#575;font-weight: bold;margin-top:5px;}
.form_rubric .plainvalue.empty {font-style: italic; color: #AAA;}
.form_rubric.editor .criterion .levels .level .delete {position:absolute;right:0px;bottom:32767px;}
.form_rubric .criterion .levels .level .score {display:block;}
/* Make invisible the buttons 'Move up' for the first criterion and 'Move down' for the last, because those buttons will make no change */ /* Make invisible the buttons 'Move up' for the first criterion and 'Move down' for the last, because those buttons will make no change */
.form_rubric.editor .criterion.first .controls .moveup input, .gradingform_rubric.editor .criterion.first .controls .moveup input,
.form_rubric.editor .criterion.last .controls .movedown input {display:none;} .gradingform_rubric.editor .criterion.last .controls .movedown input {display:none;}
/* evaluation */ /* evaluation */
.form_rubric .criterion .levels .level.checked {background:#d0ffd0;} .gradingform_rubric .criterion .levels .level.checked {background:#d0ffd0;}
.form_rubric.evaluate .criterion .levels .level:hover {background:#30ff30;} .gradingform_rubric.evaluate .criterion .levels .level:hover {background:#30ff30;}
/* replace buttons with images */ /* replace buttons with images */
.form_rubric.editor .delete input, .gradingform_rubric.editor .delete input,
.form_rubric.editor .moveup input, .gradingform_rubric.editor .moveup input,
.form_rubric.editor .movedown input{text-indent: -1000em;cursor:pointer;border:none;} .gradingform_rubric.editor .movedown input{text-indent: -1000em;cursor:pointer;border:none;}
.form_rubric.editor .criterion .controls .delete input {width:20px;height:16px;background: transparent url([[pix:i/cross_red_big]]) no-repeat center top;} .gradingform_rubric.editor .criterion .controls .delete input {width:20px;height:16px;background: transparent url([[pix:i/cross_red_big]]) no-repeat center top;}
.form_rubric.editor .levels .level .delete input {width:20px;height:16px;background: transparent url([[pix:i/cross_red_small]]) no-repeat center top;} .gradingform_rubric.editor .levels .level .delete input {width:20px;height:16px;background: transparent url([[pix:i/cross_red_small]]) no-repeat center top;}
.form_rubric.editor .moveup input {width:20px;height:15px;background: transparent url([[pix:t/up]]) no-repeat center top;margin-top:4px;} .gradingform_rubric.editor .moveup input {width:20px;height:15px;background: transparent url([[pix:t/up]]) no-repeat center top;margin-top:4px;}
.form_rubric.editor .movedown input {width:20px;height:15px;background: transparent url([[pix:t/down]]) no-repeat center top;margin-top:4px;} .gradingform_rubric.editor .movedown input {width:20px;height:15px;background: transparent url([[pix:t/down]]) no-repeat center top;margin-top:4px;}
.form_rubric.editor .addcriterion input, .gradingform_rubric.editor .addcriterion input,
.form_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 .addlevel input {background: transparent url([[pix:t/addgreen]]) no-repeat;display:block;color:#555555;font-weight:bold;text-decoration:none;}
.form_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 .addcriterion input {background-position: 5px 8px;height:30px;line-height:29px;margin-bottom:14px;padding-left:20px;padding-right:10px;}
.form_rubric.editor .addlevel input {background-position: 5px 6px;height:25px;line-height:24px;margin-bottom:10px;padding-left:18px;padding-right:8px;} .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;}