MDL-29481: added support for remarks in rubric feedback
This commit is contained in:
@@ -48,7 +48,7 @@ abstract class gradingform_controller {
|
||||
protected $areaid;
|
||||
|
||||
/** @var stdClass|false the definition structure */
|
||||
protected $definition;
|
||||
protected $definition = false;
|
||||
|
||||
/** @var array graderange array of valid grades for this area. Use set_grade_range and get_grade_range to access this */
|
||||
private $graderange = null;
|
||||
@@ -110,7 +110,7 @@ abstract class gradingform_controller {
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_form_defined() {
|
||||
return !empty($this->definition);
|
||||
return ($this->definition !== false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -181,7 +181,7 @@ abstract class gradingform_controller {
|
||||
* @return stdClass|false definition data or false if the form is not defined yet
|
||||
*/
|
||||
public function get_definition($force = false) {
|
||||
if (is_null($this->definition)) {
|
||||
if ($this->definition === false || $force) {
|
||||
$this->load_definition();
|
||||
}
|
||||
return $this->definition;
|
||||
|
||||
@@ -190,7 +190,7 @@ class gradingform_rubric_controller extends gradingform_controller {
|
||||
$this->definition = false;
|
||||
foreach ($rs as $record) {
|
||||
// pick the common definition data
|
||||
if (empty($this->definition)) {
|
||||
if ($this->definition === false) {
|
||||
$this->definition = new stdClass();
|
||||
foreach (array('id', 'name', 'description', 'descriptionformat', 'status', 'copiedfromid',
|
||||
'timecreated', 'usercreated', 'timemodified', 'usermodified', 'options') as $fieldname) {
|
||||
@@ -290,7 +290,7 @@ class gradingform_rubric_controller extends gradingform_controller {
|
||||
}
|
||||
|
||||
public function get_formatted_description() {
|
||||
if (!$this->definition) {
|
||||
if ($this->definition === false) {
|
||||
return null;
|
||||
}
|
||||
$context = $this->get_context();
|
||||
@@ -385,6 +385,8 @@ class gradingform_rubric_controller extends gradingform_controller {
|
||||
*/
|
||||
class gradingform_rubric_instance extends gradingform_instance {
|
||||
|
||||
protected $rubric;
|
||||
|
||||
/**
|
||||
* Deletes this (INCOMPLETE) instance from database.
|
||||
*/
|
||||
@@ -406,11 +408,11 @@ class gradingform_rubric_instance extends gradingform_instance {
|
||||
global $DB;
|
||||
$instanceid = parent::copy($raterid, $itemid);
|
||||
$currentgrade = $this->get_rubric_filling();
|
||||
foreach ($currentgrade as $criterionid => $levelid) {
|
||||
$params = array('forminstanceid' => $instanceid, 'criterionid' => $criterionid, 'levelid' => $levelid);
|
||||
foreach ($currentgrade['criteria'] as $criterionid => $record) {
|
||||
$params = array('forminstanceid' => $instanceid, 'criterionid' => $criterionid,
|
||||
'levelid' => $record['levelid'], 'remark' => $record['remark'], 'remarkformat' => $record['remarkformat']);
|
||||
$DB->insert_record('gradingform_rubric_fillings', $params);
|
||||
}
|
||||
// TODO remarks
|
||||
return $instanceid;
|
||||
}
|
||||
|
||||
@@ -421,11 +423,12 @@ class gradingform_rubric_instance extends gradingform_instance {
|
||||
public function validate_grading_element($elementvalue) {
|
||||
// TODO: if there is nothing selected in rubric, we don't enter this function at all :(
|
||||
$criteria = $this->get_controller()->get_definition()->rubric_criteria;
|
||||
if (!is_array($elementvalue) || sizeof($elementvalue) < sizeof($criteria)) {
|
||||
if (!isset($elementvalue['criteria']) || !is_array($elementvalue['criteria']) || sizeof($elementvalue['criteria']) < sizeof($criteria)) {
|
||||
return false;
|
||||
}
|
||||
foreach ($criteria as $id => $criterion) {
|
||||
if (!array_key_exists($id, $elementvalue) || !array_key_exists($elementvalue[$id], $criterion['levels'])) {
|
||||
if (!isset($elementvalue['criteria'][$id]['levelid'])
|
||||
|| !array_key_exists($elementvalue['criteria'][$id]['levelid'], $criterion['levels'])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -435,20 +438,19 @@ class gradingform_rubric_instance extends gradingform_instance {
|
||||
/**
|
||||
* Retrieves from DB and returns the data how this rubric was filled
|
||||
*
|
||||
* @param boolean $force whether to force DB query even if the data is cached
|
||||
* @return array
|
||||
*/
|
||||
public function get_rubric_filling() {
|
||||
// TODO cache
|
||||
public function get_rubric_filling($force = false) {
|
||||
global $DB;
|
||||
$rs = $DB->get_records('gradingform_rubric_fillings', array('forminstanceid' => $this->get_id()));
|
||||
$grading = array();
|
||||
foreach ($rs as $record) {
|
||||
if ($record->levelid) {
|
||||
$grading[$record->criterionid] = $record->levelid;
|
||||
if ($this->rubric === null || $force) {
|
||||
$records = $DB->get_records('gradingform_rubric_fillings', array('forminstanceid' => $this->get_id()));
|
||||
$this->rubric = array('criteria' => array());
|
||||
foreach ($records as $record) {
|
||||
$this->rubric['criteria'][$record->criterionid] = (array)$record;
|
||||
}
|
||||
// TODO: remarks
|
||||
}
|
||||
return $grading;
|
||||
return $this->rubric;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -460,21 +462,29 @@ class gradingform_rubric_instance extends gradingform_instance {
|
||||
global $DB;
|
||||
$currentgrade = $this->get_rubric_filling();
|
||||
parent::update($data); // TODO ? +timemodified
|
||||
foreach ($data as $criterionid => $levelid) {
|
||||
$params = array('forminstanceid' => $this->get_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 ($data['criteria'] as $criterionid => $record) {
|
||||
if (!array_key_exists($criterionid, $currentgrade['criteria'])) {
|
||||
$newrecord = array('forminstanceid' => $this->get_id(), 'criterionid' => $criterionid,
|
||||
'levelid' => $record['levelid'], 'remark' => $record['remark'], 'remarkformat' => FORMAT_MOODLE);
|
||||
$DB->insert_record('gradingform_rubric_fillings', $newrecord);
|
||||
} else {
|
||||
$newrecord = array('id' => $currentgrade['criteria'][$criterionid]['id']);
|
||||
foreach (array('levelid', 'remark'/*, 'remarkformat' TODO */) as $key) {
|
||||
if ($currentgrade['criteria'][$criterionid][$key] != $record[$key]) {
|
||||
$newrecord[$key] = $record[$key];
|
||||
}
|
||||
}
|
||||
if (count($newrecord) > 1) {
|
||||
$DB->update_record('gradingform_rubric_fillings', $newrecord);
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($currentgrade as $criterionid => $levelid) {
|
||||
if (!array_key_exists($criterionid, $data)) {
|
||||
$params = array('forminstanceid' => $this->get_id(), 'criterionid' => $criterionid);
|
||||
$DB->delete_records('gradingform_rubric_fillings', $params);
|
||||
foreach ($currentgrade['criteria'] as $criterionid => $record) {
|
||||
if (!array_key_exists($criterionid, $data['criteria'])) {
|
||||
$DB->delete_records('gradingform_rubric_fillings', array('id' => $record['id']));
|
||||
}
|
||||
}
|
||||
// TODO: remarks
|
||||
$this->get_rubric_filling(true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -508,8 +518,8 @@ class gradingform_rubric_instance extends gradingform_instance {
|
||||
$maxgrade = $graderange[sizeof($graderange) - 1];
|
||||
|
||||
$curscore = 0;
|
||||
foreach ($grade as $id => $levelid) {
|
||||
$curscore += $this->get_controller()->get_definition()->rubric_criteria[$id]['levels'][$levelid]['score'];
|
||||
foreach ($grade['criteria'] as $id => $record) {
|
||||
$curscore += $this->get_controller()->get_definition()->rubric_criteria[$id]['levels'][$record['levelid']]['score'];
|
||||
}
|
||||
return round(($curscore-$minscore)/($maxscore-$minscore)*($maxgrade-$mingrade), 0) + $mingrade; // TODO mapping
|
||||
}
|
||||
|
||||
@@ -35,8 +35,8 @@ class gradingform_rubric_renderer {
|
||||
* @param int $mode @see gradingform_rubric_controller
|
||||
* @return string
|
||||
*/
|
||||
public function criterion_template($mode, $elementname = '{NAME}', $criterion = null, $levels_str = '{LEVELS}') {
|
||||
// TODO description format
|
||||
public function criterion_template($mode, $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}');
|
||||
} else {
|
||||
@@ -74,6 +74,21 @@ class gradingform_rubric_renderer {
|
||||
'id' => '{NAME}-{CRITERION-id}-levels-addlevel', 'value' => $value, 'title' => $value)); //TODO '{NAME}-{CRITERION-id}-levels-addlevel
|
||||
$criterion_template .= html_writer::tag('div', $button, array('class' => 'addlevel'));
|
||||
}
|
||||
if (isset($value['remark'])) {
|
||||
$currentremark = $value['remark'];
|
||||
} else {
|
||||
$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('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);
|
||||
@@ -83,7 +98,7 @@ class gradingform_rubric_renderer {
|
||||
|
||||
public function level_template($mode, $elementname = '{NAME}', $criterionid = '{CRITERION-id}', $level = null) {
|
||||
// TODO definition format
|
||||
if ($level === null || !is_array($level) || !array_key_exists('id', $level)) {
|
||||
if (!isset($level['id'])) {
|
||||
$level = array('id' => '{LEVEL-id}', 'definition' => '{LEVEL-definition}', 'score' => '{LEVEL-score}', 'class' => '{LEVEL-class}', 'checked' => false);
|
||||
} else {
|
||||
foreach (array('score', 'definition', 'class', 'checked') as $key) {
|
||||
@@ -108,12 +123,12 @@ class gradingform_rubric_renderer {
|
||||
$score = $level['score'];
|
||||
}
|
||||
if ($mode == gradingform_rubric_controller::DISPLAY_EVAL) {
|
||||
$input = html_writer::empty_tag('input', array('type' => 'radio', 'name' => '{NAME}[{CRITERION-id}]', 'value' => $level['id']) +
|
||||
$input = html_writer::empty_tag('input', array('type' => 'radio', 'name' => '{NAME}[criteria][{CRITERION-id}][levelid]', 'value' => $level['id']) +
|
||||
($level['checked'] ? array('checked' => 'checked') : array()));
|
||||
$level_template .= html_writer::tag('div', $input, array('class' => 'radio'));
|
||||
}
|
||||
if ($mode == gradingform_rubric_controller::DISPLAY_EVAL_FROZEN && $level['checked']) {
|
||||
$html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => '{NAME}[{CRITERION-id}]', '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'));
|
||||
$level_template .= html_writer::tag('div', $definition, array('class' => 'definition', 'id' => '{NAME}-{CRITERION-id}-levels-{LEVEL-id}-definition'));
|
||||
@@ -176,17 +191,22 @@ class gradingform_rubric_renderer {
|
||||
$criterion['class'] = $this->get_css_class_suffix($cnt++, sizeof($criteria) -1);
|
||||
$levels_str = '';
|
||||
$levelcnt = 0;
|
||||
if (isset($values['criteria'][$id])) {
|
||||
$criterionvalue = $values['criteria'][$id];
|
||||
} else {
|
||||
$criterionvalue = null;
|
||||
}
|
||||
foreach ($criterion['levels'] as $levelid => $level) {
|
||||
$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'] = (is_array($values) && (array_key_exists($id, $values) && ((int)$values[$id] === $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)) {
|
||||
$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
|
||||
}
|
||||
$levels_str .= $this->level_template($mode, $elementname, $id, $level);
|
||||
}
|
||||
$criteria_str .= $this->criterion_template($mode, $elementname, $criterion, $levels_str);
|
||||
$criteria_str .= $this->criterion_template($mode, $elementname, $criterion, $levels_str, $criterionvalue);
|
||||
}
|
||||
return $this->rubric_template($mode, $elementname, $criteria_str);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
[input type=submit]
|
||||
.addlevel
|
||||
[input type=submit]
|
||||
.remark
|
||||
textarea
|
||||
.addcriterion
|
||||
[input type=submit]
|
||||
|
||||
@@ -41,11 +43,13 @@
|
||||
.form_rubric .criterion .description,
|
||||
.form_rubric .criterion .levels,
|
||||
.form_rubric.editor .criterion .addlevel,
|
||||
.form_rubric .criterion .remark,
|
||||
.form_rubric .criterion .levels .level {display: inline-block; vertical-align: top;overflow: hidden;}
|
||||
|
||||
.form_rubric.editor .criterion .controls,
|
||||
.form_rubric .criterion .description,
|
||||
.form_rubric.editor .criterion .addlevel,
|
||||
.form_rubric .criterion .remark,
|
||||
.form_rubric .criterion .levels .level {padding:3px;}
|
||||
|
||||
/* Those divs should extend vertically and fill 100% of parent element height */
|
||||
|
||||
Reference in New Issue
Block a user