MDL-29481: filling rubric by teacher, first steps

This commit is contained in:
Marina Glancy
2011-10-13 16:27:33 +08:00
parent a5c4c99b24
commit 3bf7ef29a5
4 changed files with 173 additions and 23 deletions
+2 -1
View File
@@ -256,6 +256,7 @@ abstract class gradingform_controller {
$instance->raterid = $raterid;
$instance->itemid = $itemid;
$instance->timemodified = time();
$instance->feedbackformat = FORMAT_MOODLE;
$instance->id = $DB->insert_record('grading_instances', $instance);
return $instance;
@@ -267,7 +268,7 @@ abstract class gradingform_controller {
/**
* Saves non-js data and returns the gradebook grade
*/
abstract public function save_and_get_grade($itemid, $formdata);
abstract public function save_and_get_grade($raterid, $itemid, $formdata);
/**
* Returns html for form element
+25
View File
@@ -0,0 +1,25 @@
M.gradingform_rubric = {};
/**
* This function is called for each rubric on page.
*/
M.gradingform_rubric.init = function(Y, options) {
Y.on('click', M.gradingform_rubric.levelclick, '#rubric-'+options.name+' .level', null, Y, options.name);
Y.all('#rubric-'+options.name+' .radio').setStyle('display', 'none')
};
M.gradingform_rubric.levelclick = function(e, Y, name) {
var el = e.target
while (el && !el.hasClass('level')) el = el.get('parentNode')
if (!el) return
e.preventDefault();
el.siblings().removeClass('checked');
chb = el.one('input[type=radio]')
if (!chb.get('checked')) {
chb.set('checked', true)
el.addClass('checked')
} else {
el.removeClass('checked');
el.get('parentNode').all('input[type=radio]').set('checked', false)
}
}
+144 -21
View File
@@ -226,39 +226,153 @@ class gradingform_rubric_controller extends gradingform_controller {
return $properties;
}
public function get_grading($raterid, $itemid) {
global $DB;
$sql = "SELECT f.id, f.criterionid, f.levelid, f.remark, f.remarkformat
FROM {grading_instances} i, {gradingform_rubric_fillings} f
WHERE i.formid = :formid ".
"AND i.raterid = :raterid ".
"AND i.itemid = :itemid
AND i.id = f.forminstanceid";
$params = array('formid' => $this->definition->id, 'itemid' => $itemid, 'raterid' => $raterid);
$rs = $DB->get_recordset_sql($sql, $params);
$grading = array();
foreach ($rs as $record) {
if ($record->levelid) {
$grading[$record->criterionid] = $record->levelid;
}
// TODO: remarks
}
return $grading;
}
/**
* Converts the rubric data to the gradebook score 0-100
*/
protected function calculate_grade($grade, $itemid) {
if (!$this->validate_grading_element($grade, $itemid)) {
return -1;
}
$minscore = 0;
$maxscore = 0;
foreach ($this->definition->rubric_criteria as $id => $criterion) {
$keys = array_keys($criterion['levels']);
// TODO array_reverse($keys) if levels are sorted DESC
$minscore += $criterion['levels'][$keys[0]]['score'];
$maxscore += $criterion['levels'][$keys[sizeof($keys)-1]]['score'];
}
if ($maxscore == 0) {
return -1;
}
$curscore = 0;
foreach ($grade as $id => $levelid) {
$curscore += $this->definition->rubric_criteria[$id]['levels'][$levelid]['score'];
}
return $curscore/$maxscore*100; // TODO mapping
}
/**
* Saves non-js data and returns the gradebook grade
*/
public function save_and_get_grade($itemid, $formdata) {
// TODO: this function is a patch at the moment!
if (is_array($formdata) && array_key_exists('grade', $formdata)) {
return $formdata['grade'];
public function save_and_get_grade($raterid, $itemid, $formdata) {
global $DB, $USER;
$instance = $this->prepare_instance($raterid, $itemid);
$currentgrade = $this->get_grading($raterid, $itemid);
if (!is_array($formdata)) {
return $this->calculate_grade($currentgrade, $itemid);
}
return -1;
foreach ($formdata as $criterionid => $levelid) {
$params = array('forminstanceid' => $instance->id, 'criterionid' => $criterionid);
if (!array_key_exists($criterionid, $currentgrade)) {
$DB->insert_record('gradingform_rubric_fillings', $params + array('levelid' => $levelid));
} else if ($currentgrade[$criterionid] != $levelid) {
$DB->set_field('gradingform_rubric_fillings', 'levelid', $levelid, $params);
}
}
foreach ($currentgrade as $criterionid => $levelid) {
if (!array_key_exists($criterionid, $formdata)) {
$params = array('forminstanceid' => $instance->id, 'criterionid' => $criterionid);
$DB->delete_records('gradingform_rubric_fillings', $params);
}
}
// TODO: remarks
return $this->calculate_grade($formdata, $itemid);
}
/**
* Returns html for form element
*/
public function to_html($gradingformelement) {
// TODO: this function is a patch at the moment!
global $PAGE, $USER;
//TODO move to renderer
//global $PAGE, $USER;
//$gradingrenderer = $this->prepare_renderer($PAGE);
$output = '';
$html = '';
$elementname = $gradingformelement->getName();
$elementvalue = $gradingformelement->getValue();
$submissionid = $gradingformelement->get_grading_attribute('submissionid');
$output .= "assessing submission $submissionid<br />";
$output .= html_writer::empty_tag('input', array('type' => 'text', 'name' => $elementname.'[grade]', 'size' => '20', 'value' => $elementvalue['grade']));
//$output .= "assessing user $userid on assignment $assignmentid<br>";
//TODO find $submissionid from $userid & $assignmentid (may not exist yet, actually)
/*$submissionid = null;
$gradingwidget = $this->make_grading_widget($USER->id, $submissionid);
if ($gradingwidget instanceof renderable) {
return $output. $gradingrenderer->render($gradingwidget);
}*/
return $output;
$raterid = $USER->id; // TODO - this is very strange!
$html .= "assessing submission $submissionid<br />";
//$html .= html_writer::empty_tag('input', array('type' => 'text', 'name' => $elementname.'[grade]', 'size' => '20', 'value' => $elementvalue['grade']));
if (!$gradingformelement->_flagFrozen) {
$module = array('name'=>'gradingform_rubric', 'fullpath'=>'/grade/grading/form/rubric/js/rubric.js');
$PAGE->requires->js_init_call('M.gradingform_rubric.init', array(array('name' => $gradingformelement->getName(), 'criteriontemplate' =>'', 'leveltemplate' => '')), true, $module);
}
$criteria = $this->definition->rubric_criteria;
$html .= html_writer::start_tag('div', array('id' => 'rubric-'.$gradingformelement->getName(), 'class' => 'form_rubric evaluate'));
$criteria_cnt = 0;
$value = $gradingformelement->getValue();
if ($value === null) {
$value = $this->get_grading($raterid, $submissionid); // TODO maybe implement in form->set_data() ?
}
foreach ($criteria as $criterionid => $criterion) {
$html .= html_writer::start_tag('div', array('class' => 'criterion'.$this->get_css_class_suffix($criteria_cnt++, count($criteria)-1)));
$html .= html_writer::tag('div', $criterion['description'], array('class' => 'description')); // TODO descriptionformat
$html .= html_writer::start_tag('div', array('class' => 'levels'));
$level_cnt = 0;
foreach ($criterion['levels'] as $levelid => $level) {
$checked = (is_array($value) && array_key_exists($criterionid, $value) && ((int)$value[$criterionid] === $levelid));
$classsuffix = $this->get_css_class_suffix($level_cnt++, count($criterion['levels'])-1);
if ($checked) {
$classsuffix .= ' checked';
}
$html .= html_writer::start_tag('div', array('id' => $gradingformelement->getName().'-'.$criterionid.'-levels-'.$levelid, 'class' => 'level'.$classsuffix));
$input = html_writer::empty_tag('input', array('type' => 'radio', 'name' => $gradingformelement->getName().'['.$criterionid.']', 'value' => $levelid) +
($checked ? array('checked' => 'checked') : array())); // TODO rewrite
$html .= html_writer::tag('div', $input, array('class' => 'radio'));
$html .= html_writer::tag('div', $level['definition'], array('class' => 'definition')); // TODO definitionformat
$html .= html_writer::tag('div', (float)$level['score'].' pts', array('class' => 'score')); //TODO span, get_string
$html .= html_writer::end_tag('div'); // .level
}
$html .= html_writer::end_tag('div'); // .levels
$html .= html_writer::end_tag('div'); // .criterion
}
$html .= html_writer::end_tag('div'); // .rubric
return $html;
}
private function get_css_class_suffix($cnt, $maxcnt) {
$class = '';
if ($cnt == 0) {
$class .= ' first';
}
if ($cnt == $maxcnt) {
$class .= ' last';
}
if ($cnt%2) {
$class .= ' odd';
} else {
$class .= ' even';
}
return $class;
}
// TODO the following functions may be moved to parent:
@@ -315,19 +429,28 @@ class gradingform_rubric_controller extends gradingform_controller {
}
/**
* Returns the error message displayed in case of validation failed
*
* @see validate_grading_element
*/
public function default_validation_error_message() {
return 'Validation failed';
return 'The rubric is incomplete'; //TODO string
}
/**
*
* Validates that rubric is fully completed and contains valid grade on each criterion
*/
public function validate_grading_element($elementvalue, $itemid) {
if ($elementvalue['grade'] > 100 || $elementvalue['grade'] < 0) {
// TODO: if there is nothing selected in rubric, we don't enter this function at all :(
$criteria = $this->definition->rubric_criteria;
if (!is_array($elementvalue) || sizeof($elementvalue) < sizeof($criteria)) {
return false;
}
foreach ($criteria as $id => $criterion) {
if (!array_key_exists($id, $elementvalue) || !array_key_exists($elementvalue[$id], $criterion['levels'])) {
return false;
}
}
return true;
}
}
+2 -1
View File
@@ -1595,6 +1595,7 @@ class assignment_base {
* If validation passes, preprocess advanced grading (if applicable) and returns true.
*/
function validate_and_preprocess_feedback() {
global $USER;
if (!$feedback = data_submitted()) {
return true; // No incoming data, nothing to validate
}
@@ -1611,7 +1612,7 @@ class assignment_base {
$data = $mform->get_data();
// TODO find better way to find submission id
$submission = $this->get_submission($userid);
$_POST['xgrade'] = $controller->save_and_get_grade($submission->id, $data->advancedgrading);
$_POST['xgrade'] = $controller->save_and_get_grade($USER->id /* TODO */, $submission->id, $data->advancedgrading);
}
}
return true;