MDL-29483, MDL-29482 advanced grading in assignment, rubrics editor
- advanced grading plugins now return the grade in the specified range - prohibited quick grading when advanced grading method is used - fixed bug in processing description in rubric editor - some improvements to rubric editor JS
This commit is contained in:
@@ -50,6 +50,9 @@ abstract class gradingform_controller {
|
||||
/** @var stdClass|false the definition structure */
|
||||
protected $definition;
|
||||
|
||||
/** @var array graderange array of valid grades for this area. Use set_grade_range and get_grade_range to access this */
|
||||
private $graderange = null;
|
||||
|
||||
/**
|
||||
* Do not instantinate this directly, use {@link grading_manager::get_controller()}
|
||||
*
|
||||
@@ -174,9 +177,10 @@ abstract class gradingform_controller {
|
||||
/**
|
||||
* Returns the grading form definition structure
|
||||
*
|
||||
* @param boolean $force whether to force loading from DB even if it was already loaded
|
||||
* @return stdClass|false definition data or false if the form is not defined yet
|
||||
*/
|
||||
public function get_definition() {
|
||||
public function get_definition($force = false) {
|
||||
if (is_null($this->definition)) {
|
||||
$this->load_definition();
|
||||
}
|
||||
@@ -459,12 +463,33 @@ abstract class gradingform_controller {
|
||||
*
|
||||
* @param moodle_page $page
|
||||
* @param int $itemid
|
||||
* @param string $defaultcontent default string to be returned if no active grading is found
|
||||
* @param array $grading_info result of function grade_get_grades if plugin want to use some of their info
|
||||
* @param string $defaultcontent default string to be returned if no active grading is found or for some reason can not be shown to a user
|
||||
* @return string
|
||||
*/
|
||||
public function render_grade($page, $itemid, $defaultcontent) {
|
||||
public function render_grade($page, $itemid, $grading_info, $defaultcontent) {
|
||||
return $defaultcontent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the range of grades used in this area. This is usually either range like 0-100
|
||||
* or the scale where keys start from 1. Typical use:
|
||||
* $controller->set_grade_range(make_grades_menu($gradingtype));
|
||||
*/
|
||||
public final function set_grade_range(array $graderange) {
|
||||
$this->graderange = $graderange;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the range of grades used in this area
|
||||
* @return array
|
||||
*/
|
||||
public final function get_grade_range() {
|
||||
if (empty($this->graderange)) {
|
||||
return array();
|
||||
}
|
||||
return $this->graderange;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -600,7 +625,8 @@ abstract class gradingform_instance {
|
||||
|
||||
/**
|
||||
* Calculates the grade to be pushed to the gradebook
|
||||
* @return int the grade on 0-100 scale
|
||||
*
|
||||
* @return int the valid grade from $this->get_controller()->get_grade_range()
|
||||
*/
|
||||
abstract public function get_grade();
|
||||
|
||||
@@ -622,11 +648,12 @@ abstract class gradingform_instance {
|
||||
* If there are more than one input elements they MUST be elements of array with
|
||||
* name $gradingformelement->getName().
|
||||
* Example: {NAME}[myelement1], {NAME}[myelement2][sub1], {NAME}[myelement2][sub2], etc.
|
||||
* ( {NAME} is a shortcut for $gradingformelement->getName() )
|
||||
* After submitting the form the value of $_POST[{NAME}] is passed to the functions
|
||||
* validate_grading_element() and submit_and_get_grade()
|
||||
*
|
||||
* Plugins may use $gradingformelement->getValue() to get the value passed on previous
|
||||
* from submit
|
||||
* form submit
|
||||
*
|
||||
* When forming html it is a plugin's responsibility to analyze flags
|
||||
* $gradingformelement->_flagFrozen and $gradingformelement->_persistantFreeze:
|
||||
|
||||
@@ -46,14 +46,13 @@ $PAGE->set_heading(get_string('definerubric', 'gradingform_rubric'));
|
||||
$PAGE->requires->js('/grade/grading/form/rubric/js/rubriceditor.js');
|
||||
|
||||
//TODO freeze rubric editor if needed
|
||||
$mform = new gradingform_rubric_editrubric(null, array('areaid' => $areaid, 'freezerubric' => optional_param('freeze', 0, PARAM_INT)));
|
||||
$mform = new gradingform_rubric_editrubric(null, array('areaid' => $areaid, 'context' => $context, 'freezerubric' => optional_param('freeze', 0, PARAM_INT)));
|
||||
$mform->set_data($controller->get_definition_for_editing());
|
||||
if ($mform->is_cancelled()) {
|
||||
// todo process editing cancel in a better way
|
||||
redirect($manager->get_management_url());
|
||||
|
||||
} else if ($data = $mform->get_data()) {
|
||||
$data = $controller->postupdate_definition_data($data);
|
||||
$controller->update_definition($data);
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ class gradingform_rubric_editrubric extends moodleform {
|
||||
$form->setType('name', PARAM_TEXT);
|
||||
|
||||
// description
|
||||
$options = array();
|
||||
$options = gradingform_rubric_controller::description_form_field_options($this->_customdata['context']);
|
||||
$form->addElement('editor', 'description_editor', get_string('description', 'gradingform_rubric'), null, $options);
|
||||
$form->setType('description_editor', PARAM_RAW);
|
||||
|
||||
|
||||
@@ -83,6 +83,7 @@ M.gradingform_rubriceditor.editmode = function(el, editmode) {
|
||||
}
|
||||
ta.get('parentNode').one('.plainvalue').setStyle('display', 'none')
|
||||
ta.setStyle('display', 'block').setStyle('width', width).setStyle('height', height)
|
||||
ta.focus()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -60,19 +60,28 @@ class gradingform_rubric_controller extends gradingform_controller {
|
||||
* Saves the rubric definition into the database
|
||||
*
|
||||
* @see parent::update_definition()
|
||||
* @param stdClass $newdefinition rubric definition data as coming from {@link self::postupdate_definition_data()}
|
||||
* @param stdClass $newdefinition rubric definition data as coming from gradingform_rubric_editrubric::get_data()
|
||||
* @param int|null $usermodified optional userid of the author of the definition, defaults to the current user
|
||||
*/
|
||||
public function update_definition(stdClass $newdefinition, $usermodified = null) {
|
||||
global $DB;
|
||||
|
||||
// firstly update the common definition data in the {grading_definition} table
|
||||
if ($this->definition === false) {
|
||||
// if definition does not exist yet, create a blank one with only required fields set
|
||||
// (we need id to save files embedded in description)
|
||||
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(),
|
||||
'gradingform_rubric', 'definition_description', $this->definition->id);
|
||||
parent::update_definition($newdefinition, $usermodified);
|
||||
// reload the definition from the database
|
||||
$this->load_definition();
|
||||
$currentdefinition = $this->get_definition();
|
||||
|
||||
// update current data
|
||||
// reload the definition from the database
|
||||
$currentdefinition = $this->get_definition(true);
|
||||
|
||||
// update rubric data
|
||||
$haschanges = false;
|
||||
if (empty($newdefinition->rubric_criteria)) {
|
||||
$newcriteria = array();
|
||||
@@ -299,21 +308,6 @@ class gradingform_rubric_controller extends gradingform_controller {
|
||||
return format_text($description, $this->definition->descriptionformat, $formatoptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the rubric definition data from the submitted form back to the form
|
||||
* suitable for storing in database
|
||||
*/
|
||||
public function postupdate_definition_data($data) {
|
||||
if (!$this->definition) {
|
||||
return $data;
|
||||
}
|
||||
$options = self::description_form_field_options($this->get_context());
|
||||
$data = file_postupdate_standard_editor($data, 'description', $options, $this->get_context(),
|
||||
'gradingform_rubric', 'definition_description', $this->definition->id);
|
||||
// TODO change filearea for embedded files in grading_definition.description
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function is_form_available($foruserid = null) {
|
||||
return true;
|
||||
// TODO this is temporary for testing!
|
||||
@@ -373,10 +367,11 @@ class gradingform_rubric_controller extends gradingform_controller {
|
||||
*
|
||||
* @param moodle_page $page
|
||||
* @param int $itemid
|
||||
* @param array $grading_info result of function grade_get_grades
|
||||
* @param string $defaultcontent default string to be returned if no active grading is found
|
||||
* @return string
|
||||
*/
|
||||
public function render_grade($page, $itemid, $defaultcontent) {
|
||||
public function render_grade($page, $itemid, $grading_info, $defaultcontent) {
|
||||
$instances = $this->get_current_instances($itemid);
|
||||
return $this->get_renderer($page)->display_instances($this->get_current_instances($itemid), $defaultcontent);
|
||||
}
|
||||
@@ -484,7 +479,8 @@ class gradingform_rubric_instance extends gradingform_instance {
|
||||
|
||||
/**
|
||||
* Calculates the grade to be pushed to the gradebook
|
||||
* @return int the grade on 0-100 scale
|
||||
*
|
||||
* @return int the valid grade from $this->get_controller()->get_grade_range()
|
||||
*/
|
||||
public function get_grade() {
|
||||
global $DB, $USER;
|
||||
@@ -494,20 +490,28 @@ class gradingform_rubric_instance extends gradingform_instance {
|
||||
$maxscore = 0;
|
||||
foreach ($this->get_controller()->get_definition()->rubric_criteria as $id => $criterion) {
|
||||
$keys = array_keys($criterion['levels']);
|
||||
// TODO array_reverse($keys) if levels are sorted DESC
|
||||
sort($keys);
|
||||
$minscore += $criterion['levels'][$keys[0]]['score'];
|
||||
$maxscore += $criterion['levels'][$keys[sizeof($keys)-1]]['score'];
|
||||
}
|
||||
|
||||
if ($maxscore == 0) {
|
||||
if ($maxscore <= $minscore) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
$graderange = array_keys($this->get_controller()->get_grade_range());
|
||||
if (empty($graderange)) {
|
||||
return -1;
|
||||
}
|
||||
sort($graderange);
|
||||
$mingrade = $graderange[0];
|
||||
$maxgrade = $graderange[sizeof($graderange) - 1];
|
||||
|
||||
$curscore = 0;
|
||||
foreach ($grade as $id => $levelid) {
|
||||
$curscore += $this->get_controller()->get_definition()->rubric_criteria[$id]['levels'][$levelid]['score'];
|
||||
}
|
||||
return $curscore/$maxscore*100; // TODO mapping
|
||||
return round(($curscore-$minscore)/($maxscore-$minscore)*($maxgrade-$mingrade), 0) + $mingrade; // TODO mapping
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+29
-7
@@ -332,7 +332,8 @@ class assignment_base {
|
||||
echo '<td class="content">';
|
||||
$grade_str = '<div class="grade">'. get_string("grade").': '.$grade->str_long_grade. '</div>';
|
||||
if (!empty($submission) && $controller = get_grading_manager($this->context, 'mod_assignment', 'submission')->get_active_controller()) {
|
||||
echo $controller->render_grade($PAGE, $submission->id, $grade_str);
|
||||
$controller->set_grade_range(make_grades_menu($this->assignment->grade));
|
||||
echo $controller->render_grade($PAGE, $submission->id, $item, $grade_str);
|
||||
} else {
|
||||
echo $grade_str;
|
||||
}
|
||||
@@ -780,6 +781,23 @@ class assignment_base {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if grading method allows quickgrade mode. At the moment it is hardcoded
|
||||
* that advanced grading methods do not allow quickgrade.
|
||||
*
|
||||
* Assignment type plugins are not allowed to override this method
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public final function quickgrade_mode_allowed() {
|
||||
global $CFG;
|
||||
require_once("$CFG->dirroot/grade/grading/lib.php");
|
||||
if ($controller = get_grading_manager($this->context, 'mod_assignment', 'submission')->get_active_controller()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method updating the listing on the main script from popup using javascript
|
||||
*
|
||||
@@ -794,7 +812,7 @@ class assignment_base {
|
||||
|
||||
$perpage = get_user_preferences('assignment_perpage', 10);
|
||||
|
||||
$quickgrade = get_user_preferences('assignment_quickgrade', 0);
|
||||
$quickgrade = get_user_preferences('assignment_quickgrade', 0) && $this->quickgrade_mode_allowed();
|
||||
|
||||
/// Run some Javascript to try and update the parent page
|
||||
$output .= '<script type="text/javascript">'."\n<!--\n";
|
||||
@@ -1138,7 +1156,7 @@ class assignment_base {
|
||||
* from database
|
||||
*/
|
||||
$perpage = get_user_preferences('assignment_perpage', 10);
|
||||
$quickgrade = get_user_preferences('assignment_quickgrade', 0);
|
||||
$quickgrade = get_user_preferences('assignment_quickgrade', 0) && $this->quickgrade_mode_allowed();
|
||||
$filter = get_user_preferences('assignment_filter', 0);
|
||||
$grading_info = grade_get_grades($this->course->id, 'mod', 'assignment', $this->assignment->id);
|
||||
|
||||
@@ -1367,6 +1385,7 @@ class assignment_base {
|
||||
|
||||
/// Calculate user status
|
||||
$auser->status = ($auser->timemarked > 0) && ($auser->timemarked >= $auser->timemodified);
|
||||
// TODO add here code if advanced grading grade must be reviewed => $auser->status=0
|
||||
$picture = $OUTPUT->user_picture($auser);
|
||||
|
||||
if (empty($auser->submissionid)) {
|
||||
@@ -1552,9 +1571,11 @@ class assignment_base {
|
||||
$mform->addElement('text', 'perpage', get_string('pagesize', 'assignment'), array('size'=>1));
|
||||
$mform->setDefault('perpage', $perpage);
|
||||
|
||||
$mform->addElement('checkbox', 'quickgrade', get_string('quickgrade','assignment'));
|
||||
$mform->setDefault('quickgrade', $quickgrade);
|
||||
$mform->addHelpButton('quickgrade', 'quickgrade', 'assignment');
|
||||
if ($this->quickgrade_mode_allowed()) {
|
||||
$mform->addElement('checkbox', 'quickgrade', get_string('quickgrade','assignment'));
|
||||
$mform->setDefault('quickgrade', $quickgrade);
|
||||
$mform->addHelpButton('quickgrade', 'quickgrade', 'assignment');
|
||||
}
|
||||
|
||||
$mform->addElement('submit', 'savepreferences', get_string('savepreferences'));
|
||||
|
||||
@@ -2352,11 +2373,12 @@ class mod_assignment_grading_form extends moodleform {
|
||||
|
||||
$mform->addElement('header', 'Grades', get_string('grades', 'grades'));
|
||||
|
||||
$grademenu = make_grades_menu($this->_customdata->assignment->grade);
|
||||
if ($gradinginstance = $this->use_advanced_grading()) {
|
||||
$gradinginstance->get_controller()->set_grade_range($grademenu);
|
||||
$mform->addElement('grading', 'advancedgrading', get_string('grade').':', array('gradinginstance' => $gradinginstance));
|
||||
} else {
|
||||
// use simple direct grading
|
||||
$grademenu = make_grades_menu($this->_customdata->assignment->grade);
|
||||
$grademenu['-1'] = get_string('nograde');
|
||||
|
||||
$mform->addElement('select', 'xgrade', get_string('grade').':', $grademenu, $attributes);
|
||||
|
||||
Reference in New Issue
Block a user