diff --git a/grade/grading/form/lib.php b/grade/grading/form/lib.php index da2d405aa87..97cfe3bc4e1 100644 --- a/grade/grading/form/lib.php +++ b/grade/grading/form/lib.php @@ -56,6 +56,9 @@ abstract class gradingform_controller { /** @var array graderange array of valid grades for this area. Use set_grade_range and get_grade_range to access this */ private $graderange = null; + /** @var boolean|null cached result of function has_active_instances() */ + protected $hasactiveinstances = null; + /** * Do not instantinate this directly, use {@link grading_manager::get_controller()} * @@ -334,8 +337,8 @@ abstract class gradingform_controller { } /** - * Returns the ACTIVE instance for this definition for the specified $raterid and $itemid - * (if multiple raters are allowed, or only for $itemid otherwise). + * Returns the current instance (either with status ACTIVE or NEEDUPDATE) for this definition for the + * specified $raterid and $itemid (if multiple raters are allowed, or only for $itemid otherwise). * * @param int $raterid * @param int $itemid @@ -344,19 +347,22 @@ abstract class gradingform_controller { */ public function get_current_instance($raterid, $itemid, $idonly = false) { global $DB; - $select = array( + $params = array( 'formid' => $this->definition->id, 'itemid' => $itemid, - 'status' => gradingform_instance::INSTANCE_STATUS_ACTIVE); + 'status1' => gradingform_instance::INSTANCE_STATUS_ACTIVE, + 'status2' => gradingform_instance::INSTANCE_STATUS_NEEDUPDATE); + $select = 'formid=:formid and itemid=:itemid and (status=:status1 or status=:status2)'; if (false /* TODO $manager->allow_multiple_raters() */) { - $select['raterid'] = $raterid; + $select .= ' and raterid=:raterid'; + $params['raterid'] = $raterid; } if ($idonly) { - if ($current = $DB->get_record('grading_instances', $select, 'id', IGNORE_MISSING)) { + if ($current = $DB->get_record_select('grading_instances', $select, $params, 'id', IGNORE_MISSING)) { return $current->id; } } else { - if ($current = $DB->get_record('grading_instances', $select, '*', IGNORE_MISSING)) { + if ($current = $DB->get_record_select('grading_instances', $select, $params, '*', IGNORE_MISSING)) { return $this->get_instance($current); } } @@ -364,12 +370,13 @@ abstract class gradingform_controller { } /** - * Returns list of active instances for the specified $itemid + * Returns list of ACTIVE instances for the specified $itemid + * (intentionally does not return instances with status NEEDUPDATE) * * @param int $itemid * @return array of gradingform_instance objects */ - public function get_current_instances($itemid) { + public function get_active_instances($itemid) { global $DB; $conditions = array('formid' => $this->definition->id, 'itemid' => $itemid, @@ -382,6 +389,22 @@ abstract class gradingform_controller { return $rv; } + /** + * Returns true if there are already people who has been graded on this definition. + * In this case plugins may restrict changes of the grading definition + * + * @return boolean + */ + public function has_active_instances() { + global $DB; + if ($this->hasactiveinstances === null) { + $conditions = array('formid' => $this->definition->id, + 'status' => gradingform_instance::INSTANCE_STATUS_ACTIVE); + $this->hasactiveinstances = $DB->record_exists('grading_instances', $conditions); + } + return $this->hasactiveinstances; + } + /** * Returns the object of type gradingform_XXX_instance (where XXX is the plugin method name) * @@ -528,9 +551,10 @@ abstract class gradingform_controller { * @param int $itemid * @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 + * @param boolean $cangrade whether current user has capability to grade in this context * @return string */ - public function render_grade($page, $itemid, $grading_info, $defaultcontent) { + public function render_grade($page, $itemid, $grading_info, $defaultcontent, $cangrade) { return $defaultcontent; } @@ -563,6 +587,7 @@ abstract class gradingform_controller { */ abstract class gradingform_instance { const INSTANCE_STATUS_ACTIVE = 1; + const INSTANCE_STATUS_NEEDUPDATE = 2; const INSTANCE_STATUS_INCOMPLETE = 0; const INSTANCE_STATUS_ARCHIVE = 3; @@ -624,6 +649,19 @@ abstract class gradingform_instance { return $instanceid; } + /** + * Returns the current (active or needupdate) instance for the same raterid and itemid as this + * instance. This function is useful to find the status of the currently modified instance + * + * @return gradingform_instance + */ + public function get_current_instance() { + if ($this->get_status() == self::INSTANCE_STATUS_ACTIVE || $this->get_status() == self::INSTANCE_STATUS_NEEDUPDATE) { + return $this; + } + return $this->get_controller()->get_current_instance($this->data->raterid, $this->data->itemid); + } + /** * Returns the controller * @@ -642,6 +680,15 @@ abstract class gradingform_instance { return $this->data->id; } + /** + * Returns instance status + * + * @return int + */ + public function get_status() { + return $this->data->status; + } + /** * Marks the instance as ACTIVE and current active instance (if exists) as ARCHIVE */ @@ -655,14 +702,10 @@ abstract class gradingform_instance { throw new coding_exception('You cannot mark active the grading instance without itemid'); } $currentid = $this->get_controller()->get_current_instance($this->data->raterid, $this->data->itemid, true); - if ($currentid) { - if ($currentid != $this->get_id()) { - $DB->update_record('grading_instances', array('id' => $currentid, 'status' => self::INSTANCE_STATUS_ARCHIVE)); - $DB->update_record('grading_instances', array('id' => $this->get_id(), 'status' => self::INSTANCE_STATUS_ACTIVE)); - } - } else { - $DB->update_record('grading_instances', array('id' => $this->get_id(), 'status' => self::INSTANCE_STATUS_ACTIVE)); + if ($currentid && $currentid != $this->get_id()) { + $DB->update_record('grading_instances', array('id' => $currentid, 'status' => self::INSTANCE_STATUS_ARCHIVE)); } + $DB->update_record('grading_instances', array('id' => $this->get_id(), 'status' => self::INSTANCE_STATUS_ACTIVE)); $this->data->status = self::INSTANCE_STATUS_ACTIVE; } diff --git a/grade/grading/form/rubric/edit.php b/grade/grading/form/rubric/edit.php index 005f27ed208..d9390bb1e8e 100644 --- a/grade/grading/form/rubric/edit.php +++ b/grade/grading/form/rubric/edit.php @@ -44,16 +44,16 @@ $PAGE->set_url(new moodle_url('/grade/grading/form/rubric/edit.php', array('area $PAGE->set_title(get_string('definerubric', 'gradingform_rubric')); $PAGE->set_heading(get_string('definerubric', 'gradingform_rubric')); -$mform = new gradingform_rubric_editrubric(null, array('areaid' => $areaid, 'context' => $context)); +$mform = new gradingform_rubric_editrubric(null, array('areaid' => $areaid, 'context' => $context, 'allowdraft' => !$controller->has_active_instances())); $data = $controller->get_definition_for_editing(); $returnurl = optional_param('returnurl', $manager->get_management_url(), PARAM_LOCALURL); $data->returnurl = $returnurl; $mform->set_data($data); if ($mform->is_cancelled()) { redirect($returnurl); -} else if ($mform->is_submitted() && $mform->is_validated()) { - $data = $mform->get_data(); - $controller->update_definition($data); +} else if ($mform->is_submitted() && $mform->is_validated() && !$mform->need_confirm_regrading($controller)) { + // everything ok, validated, re-grading confirmed if needed. Make changes to the rubric + $controller->update_definition($mform->get_data()); redirect($returnurl); } diff --git a/grade/grading/form/rubric/edit_form.php b/grade/grading/form/rubric/edit_form.php index 3dd1d3347fb..2e88088385e 100644 --- a/grade/grading/form/rubric/edit_form.php +++ b/grade/grading/form/rubric/edit_form.php @@ -69,7 +69,12 @@ class gradingform_rubric_editrubric extends moodleform { $buttonarray = array(); $buttonarray[] = &$form->createElement('submit', 'saverubric', get_string('saverubric', 'gradingform_rubric')); - $buttonarray[] = &$form->createElement('submit', 'saverubricdraft', get_string('saverubricdraft', 'gradingform_rubric')); + if ($this->_customdata['allowdraft']) { + $buttonarray[] = &$form->createElement('submit', 'saverubricdraft', get_string('saverubricdraft', 'gradingform_rubric')); + } + $editbutton = &$form->createElement('submit', 'editrubric', ' '); + $editbutton->freeze(); + $buttonarray[] = &$editbutton; $buttonarray[] = &$form->createElement('cancel'); $form->addGroup($buttonarray, 'buttonar', '', array(' '), false); $form->closeHeaderBefore('buttonar'); @@ -93,6 +98,9 @@ class gradingform_rubric_editrubric extends moodleform { if ($rubricel->non_js_button_pressed($data['rubric'])) { // if JS is disabled and button such as 'Add criterion' is pressed - prevent from submit $err['rubricdummy'] = 1; + } else if (isset($data['editrubric'])) { + // continue editing + $err['rubricdummy'] = 1; } else if (isset($data['saverubric']) && $data['saverubric']) { // If user attempts to make rubric active - it needs to be validated if ($rubricel->validate($data['rubric']) !== false) { @@ -117,4 +125,70 @@ class gradingform_rubric_editrubric extends moodleform { } return $data; } + + /** + * Check if there are changes in the rubric and it is needed to ask user whether to + * mark the current grades for re-grading. User may confirm re-grading and continue, + * return to editing or cancel the changes + * + * @param gradingform_rubric_controller $controller + */ + function need_confirm_regrading($controller) { + $data = $this->get_data(); + if (isset($data->rubric['regrade'])) { + // we have already displayed the confirmation on the previous step + return false; + } + if (!isset($data->saverubric) || !$data->saverubric) { + // we only need confirmation when button 'Save rubric' is pressed + return false; + } + if (!$controller->has_active_instances()) { + // nothing to re-grade, confirmation not needed + return false; + } + $changelevel = $controller->update_or_check_rubric($data); + if ($changelevel == 0) { + // no changes in the rubric, no confirmation needed + return false; + } + + // freeze form elements and pass the values in hidden fields + // TODO description_editor does not freeze the normal way! + $form = $this->_form; + foreach (array('rubric', 'name'/*, 'description_editor'*/) as $fieldname) { + $el =& $form->getElement($fieldname); + $el->freeze(); + $el->setPersistantFreeze(true); + if ($fieldname == 'rubric') { + $el->add_regrade_confirmation($changelevel); + } + } + + // replace button text 'saverubric' and unfreeze 'Back to edit' button + $this->findButton('saverubric')->setValue(get_string('continue')); + $el =& $this->findButton('editrubric'); + $el->setValue(get_string('backtoediting', 'gradingform_rubric')); + $el->unfreeze(); + + return true; + } + + /** + * Returns a form element (submit button) with the name $elementname + * + * @param string $elementname + * @return HTML_QuickForm_element + */ + function &findButton($elementname) { + $form = $this->_form; + $buttonar =& $form->getElement('buttonar'); + $elements =& $buttonar->getElements(); + foreach ($elements as $el) { + if ($el->getName() == $elementname) { + return $el; + } + } + return null; + } } diff --git a/grade/grading/form/rubric/lang/en/gradingform_rubric.php b/grade/grading/form/rubric/lang/en/gradingform_rubric.php index ec209a35f46..91e2bd984d4 100644 --- a/grade/grading/form/rubric/lang/en/gradingform_rubric.php +++ b/grade/grading/form/rubric/lang/en/gradingform_rubric.php @@ -69,3 +69,18 @@ $string['err_nodescription'] = 'Criterion description can not be empty'; $string['err_nodefinition'] = 'Level definition can not be empty'; $string['err_scoreformat'] = 'Number of points for each level must be a valid non-negative number'; $string['err_totalscore'] = 'Maximum number of points possible when graded by the rubric must be more than zero'; + +$string['regrademessage1'] = 'You are about to save changes to the rubric that has already been used for grading. Please indicate whether your changes + are significant and students grades need to be reviewed. + If students already graded are marked for re-grading their + current grades remain in gradebook but the students will not see the rubric grading before teacher updates it.'; +$string['regrademessage5'] = 'You are about to save significant changes to the rubric that has already been used for grading. Please note that all students already graded will be marked for re-grading. + The + current grades remain in gradebook but the students will not see the rubric grading before teacher updates it.'; +$string['regradeoption0'] = 'Do not mark for regrade'; +$string['regradeoption1'] = 'Mark for regrade'; + +$string['needregrademessage'] = 'Rubric definition was changed after this student had been graded. You must update the grade otherwise it will not be shown to student.'; +$string['rubricnotcompleted'] = 'You have to select a feedback on each rubric criterion'; + +$string['backtoediting'] = 'Back to editing'; \ No newline at end of file diff --git a/grade/grading/form/rubric/lib.php b/grade/grading/form/rubric/lib.php index 5fd07e32a6c..512e005af9a 100644 --- a/grade/grading/form/rubric/lib.php +++ b/grade/grading/form/rubric/lib.php @@ -65,10 +65,36 @@ class gradingform_rubric_controller extends gradingform_controller { * @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) { + $this->update_or_check_rubric($newdefinition, $usermodified, true); + if (isset($newdefinition->rubric['regrade']) && $newdefinition->rubric['regrade']) { + $this->mark_for_regrade(); + } + } + + /** + * Either saves the rubric definition into the database or check if it has been changed. + * Returns the level of changes: + * 0 - no changes + * 1 - only texts or criteria sortorders are changed, students probably do not require re-grading + * 2 - added levels but maximum score on rubric is the same, students still may not require re-grading + * 3 - removed criteria or added levels or changed number of points, students require re-grading but may be re-graded automatically + * 4 - removed levels - students require re-grading and not all students may be re-graded automatically + * 5 - added criteria - all students require manual re-grading + * + * @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 + * @param boolean $doupdate if true actually updates DB, otherwise performs a check + * + */ + public function update_or_check_rubric(stdClass $newdefinition, $usermodified = null, $doupdate = false) { global $DB; // firstly update the common definition data in the {grading_definition} table if ($this->definition === false) { + if (!$doupdate) { + // if we create the new definition there is no such thing as re-grading anyway + return 5; + } // if definition does not exist yet, create a blank one // (we need id to save files embedded in description) parent::update_definition(new stdClass(), $usermodified); @@ -81,13 +107,12 @@ class gradingform_rubric_controller extends gradingform_controller { $editoroptions = self::description_form_field_options($this->get_context()); $newdefinition = file_postupdate_standard_editor($newdefinition, 'description', $editoroptions, $this->get_context(), 'gradingform_rubric', 'definition_description', $this->definition->id); - parent::update_definition($newdefinition, $usermodified); // reload the definition from the database $currentdefinition = $this->get_definition(true); // update rubric data - $haschanges = false; + $haschanges = array(); if (empty($newdefinition->rubric['criteria'])) { $newcriteria = array(); } else { @@ -102,6 +127,7 @@ class gradingform_rubric_controller extends gradingform_controller { if (array_key_exists('levels', $criterion)) { $levelsdata = $criterion['levels']; } + $criterionmaxscore = null; if (preg_match('/^NEWID\d+$/', $id)) { // insert criterion into DB $data = array('formid' => $this->definition->id, 'descriptionformat' => FORMAT_MOODLE); // TODO format is not supported yet @@ -110,8 +136,10 @@ class gradingform_rubric_controller extends gradingform_controller { $data[$key] = $criterion[$key]; } } - $id = $DB->insert_record('gradingform_rubric_criteria', $data); - $haschanges = true; + if ($doupdate) { + $id = $DB->insert_record('gradingform_rubric_criteria', $data); + } + $haschanges[5] = true; } else { // update criterion in DB $data = array(); @@ -123,14 +151,21 @@ class gradingform_rubric_controller extends gradingform_controller { if (!empty($data)) { // update only if something is changed $data['id'] = $id; - $DB->update_record('gradingform_rubric_criteria', $data); - $haschanges = true; + if ($doupdate) { + $DB->update_record('gradingform_rubric_criteria', $data); + } + $haschanges[1] = true; } - // remove deleted levels from DB - foreach (array_keys($currentcriteria[$id]['levels']) as $levelid) { + // remove deleted levels from DB and calculate the maximum score for this criteria + foreach ($currentcriteria[$id]['levels'] as $levelid => $currentlevel) { + if ($criterionmaxscore === null || $criterionmaxscore < $currentlevel['score']) { + $criterionmaxscore = $currentlevel['score']; + } if (!array_key_exists($levelid, $levelsdata)) { - $DB->delete_records('gradingform_rubric_levels', array('id' => $levelid)); - $haschanges = true; + if ($doupdate) { + $DB->delete_records('gradingform_rubric_levels', array('id' => $levelid)); + } + $haschanges[4] = true; } } } @@ -150,8 +185,15 @@ class gradingform_rubric_controller extends gradingform_controller { $data[$key] = $level[$key]; } } - $levelid = $DB->insert_record('gradingform_rubric_levels', $data); - $haschanges = true; + if ($doupdate) { + $levelid = $DB->insert_record('gradingform_rubric_levels', $data); + } + if ($criterionmaxscore !== null && $criterionmaxscore >= $level['score']) { + // new level is added but the maximum score for this criteria did not change, re-grading may not be necessary + $haschanges[2] = true; + } else { + $haschanges[3] = true; + } } else { // update level in DB $data = array(); @@ -163,8 +205,13 @@ class gradingform_rubric_controller extends gradingform_controller { if (!empty($data)) { // update only if something is changed $data['id'] = $levelid; - $DB->update_record('gradingform_rubric_levels', $data); - $haschanges = true; + if ($doupdate) { + $DB->update_record('gradingform_rubric_levels', $data); + } + if (isset($data['score'])) { + $haschanges[3] = true; + } + $haschanges[1] = true; } } } @@ -172,12 +219,41 @@ class gradingform_rubric_controller extends gradingform_controller { // remove deleted criteria from DB foreach (array_keys($currentcriteria) as $id) { if (!array_key_exists($id, $newcriteria)) { - $DB->delete_records('gradingform_rubric_criteria', array('id' => $id)); - $DB->delete_records('gradingform_rubric_levels', array('criterionid' => $id)); - $haschanges = true; + if ($doupdate) { + $DB->delete_records('gradingform_rubric_criteria', array('id' => $id)); + $DB->delete_records('gradingform_rubric_levels', array('criterionid' => $id)); + } + $haschanges[3] = true; } } - $this->load_definition(); + foreach (array('status', 'description', 'descriptionformat', 'name', 'options') as $key) { + if (isset($newdefinition->$key) && $newdefinition->$key != $this->definition->$key) { + $haschanges[1] = true; + } + } + if ($usermodified && $usermodified != $this->definition->usermodified) { + $haschanges[1] = true; + } + if (!count($haschanges)) { + return 0; + } + if ($doupdate) { + parent::update_definition($newdefinition, $usermodified); + $this->load_definition(); + } + // return the maximum level of changes + $changelevels = array_keys($haschanges); + sort($changelevels); + return array_pop($changelevels); + } + + public function mark_for_regrade() { + global $DB; + if ($this->has_active_instances()) { + $conditions = array('formid' => $this->definition->id, + 'status' => gradingform_instance::INSTANCE_STATUS_ACTIVE); + $DB->set_field('grading_instances', 'status', gradingform_instance::INSTANCE_STATUS_NEEDUPDATE, $conditions); + } } /** @@ -321,8 +397,6 @@ class gradingform_rubric_controller extends gradingform_controller { return $new; } - // TODO the following functions may be moved to parent: - /** * @return array options for the form description field */ @@ -416,11 +490,11 @@ class gradingform_rubric_controller extends gradingform_controller { * @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 + * @param boolean $cangrade whether current user has capability to grade in this context * @return string */ - 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); + public function render_grade($page, $itemid, $grading_info, $defaultcontent, $cangrade) { + return $this->get_renderer($page)->display_instances($this->get_active_instances($itemid), $defaultcontent, $cangrade); } //// full-text search support ///////////////////////////////////////////// @@ -508,7 +582,6 @@ class gradingform_rubric_instance extends gradingform_instance { * @return boolean true if the form data is validated and contains no errors */ 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 (!isset($elementvalue['criteria']) || !is_array($elementvalue['criteria']) || sizeof($elementvalue['criteria']) < sizeof($criteria)) { return false; @@ -554,12 +627,15 @@ class gradingform_rubric_instance extends gradingform_instance { 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); + 'levelid' => $record['levelid'], 'remarkformat' => FORMAT_MOODLE); + if (isset($record['remark'])) { + $newrecord['remark'] = $record['remark']; + } $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]) { + if (isset($record[$key]) && $currentgrade['criteria'][$criterionid][$key] != $record[$key]) { $newrecord[$key] = $record[$key]; } } @@ -616,15 +692,6 @@ class gradingform_rubric_instance extends gradingform_instance { return round(($curscore-$minscore)/($maxscore-$minscore)*($maxgrade-$mingrade), 0) + $mingrade; // TODO mapping } - /** - * Returns the error message displayed in case of validation failed - * - * @return string - */ - public function default_validation_error_message() { - return 'The rubric is incomplete'; //TODO string - } - /** * Returns html for form element of type 'grading'. * @@ -648,10 +715,18 @@ class gradingform_rubric_instance extends gradingform_instance { $criteria = $this->get_controller()->get_definition()->rubric_criteria; $options = $this->get_controller()->get_options(); $value = $gradingformelement->getValue(); + $html = ''; if ($value === null) { $value = $this->get_rubric_filling(); + } else if (!$this->validate_grading_element($value)) { + $html .= html_writer::tag('div', get_string('rubricnotcompleted', 'gradingform_rubric'), array('class' => 'gradingform_rubric-error')); } - return $this->get_controller()->get_renderer($page)->display_rubric($criteria, $options, $mode, $gradingformelement->getName(), $value); + $currentinstance = $this->get_current_instance(); + if ($currentinstance && $currentinstance->get_status() == gradingform_instance::INSTANCE_STATUS_NEEDUPDATE) { + $html .= html_writer::tag('div', get_string('needregrademessage', 'gradingform_rubric'), array('class' => 'gradingform_rubric-regrade')); + } + $html .= $this->get_controller()->get_renderer($page)->display_rubric($criteria, $options, $mode, $gradingformelement->getName(), $value); + return $html; } } diff --git a/grade/grading/form/rubric/renderer.php b/grade/grading/form/rubric/renderer.php index 65bcf4e7e72..622520f454e 100644 --- a/grade/grading/form/rubric/renderer.php +++ b/grade/grading/form/rubric/renderer.php @@ -296,16 +296,16 @@ class gradingform_rubric_renderer extends plugin_renderer_base { } break; default: + if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FROZEN && $value) { + $html .= html_writer::empty_tag('input', $attrs + array('type' => 'hidden', 'value' => $value)); + } // 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) { + if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FROZEN || $mode == gradingform_rubric_controller::DISPLAY_PREVIEW) { $attrs['disabled'] = 'disabled'; unset($attrs['name']); } @@ -391,14 +391,16 @@ class gradingform_rubric_renderer extends plugin_renderer_base { * * @param array $instances array of objects of type gradingform_rubric_instance * @param string $defaultcontent default string that would be displayed without advanced grading + * @param boolean $cangrade whether current user has capability to grade in this context * @return string */ - public function display_instances($instances, $defaultcontent) { + public function display_instances($instances, $defaultcontent, $cangrade) { + $rv = ''; if (sizeof($instances)) { - $rv = html_writer::start_tag('div', array('class' => 'advancedgrade')); + $rv .= html_writer::start_tag('div', array('class' => 'advancedgrade')); $idx = 0; foreach ($instances as $instance) { - $rv .= $this->display_instance($instance, $idx++); + $rv .= $this->display_instance($instance, $idx++, $cangrade); } $rv .= html_writer::end_tag('div'); } @@ -410,12 +412,34 @@ class gradingform_rubric_renderer extends plugin_renderer_base { * * @param gradingform_rubric_instance $instance * @param int idx unique number of instance on page + * @param boolean $cangrade whether current user has capability to grade in this context */ - public function display_instance(gradingform_rubric_instance $instance, $idx) { + public function display_instance(gradingform_rubric_instance $instance, $idx, $cangrade) { $criteria = $instance->get_controller()->get_definition()->rubric_criteria; $options = $instance->get_controller()->get_options(); $values = $instance->get_rubric_filling(); - // 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); + if ($cangrade) { + $mode = gradingform_rubric_controller::DISPLAY_REVIEW; + } else { + $mode = gradingform_rubric_controller::DISPLAY_VIEW; + } + return $this->display_rubric($criteria, $options, $mode, 'rubric'.$idx, $values); + } + + public function display_regrade_confirmation($elementname, $changelevel, $value) { + $html = html_writer::start_tag('div', array('class' => 'gradingform_rubric-regrade')); + if ($changelevel<=2) { + $html .= get_string('regrademessage1', 'gradingform_rubric'); + $selectoptions = array( + 0 => get_string('regradeoption0', 'gradingform_rubric'), + 1 => get_string('regradeoption1', 'gradingform_rubric') + ); + $html .= html_writer::select($selectoptions, $elementname.'[regrade]', $value, false); + } else { + $html .= get_string('regrademessage5', 'gradingform_rubric'); + $html .= html_writer::empty_tag('input', array('name' => $elementname.'[regrade]', 'value' => 1, 'type' => 'hidden')); + } + $html .= html_writer::end_tag('div'); + return $html; } } diff --git a/grade/grading/form/rubric/rubriceditor.php b/grade/grading/form/rubric/rubriceditor.php index 83126ba4e33..c0a1d86e904 100644 --- a/grade/grading/form/rubric/rubriceditor.php +++ b/grade/grading/form/rubric/rubriceditor.php @@ -44,6 +44,23 @@ class MoodleQuickForm_rubriceditor extends HTML_QuickForm_input { return 'default'; } + protected $regradeconfirmation = false; + /** + * Specifies that confirmation about re-grading needs to be added to this rubric editor. + * $changelevel is saved in $this->regradeconfirmation and retrieved in toHtml() + * + * @see gradingform_rubric_controller::update_or_check_rubric() + * @param int $changelevel + */ + function add_regrade_confirmation($changelevel) { + $this->regradeconfirmation = $changelevel; + } + + /** + * Returns html string to display this element + * + * @return string + */ function toHtml() { global $PAGE; $html = $this->_getTabs(); @@ -69,6 +86,12 @@ class MoodleQuickForm_rubriceditor extends HTML_QuickForm_input { $mode = gradingform_rubric_controller::DISPLAY_PREVIEW; } } + if ($this->regradeconfirmation) { + if (!isset($data['regrade'])) { + $data['regrade'] = 1; + } + $html .= $renderer->display_regrade_confirmation($this->getName(), $this->regradeconfirmation, $data['regrade']); + } if ($this->validationerrors) { $html .= $renderer->notification($this->validationerrors, 'error'); } @@ -114,6 +137,14 @@ class MoodleQuickForm_rubriceditor extends HTML_QuickForm_input { } } } + if (is_array($value)) { + // for other array keys of $value no special treatmeant neeeded, copy them to return value as is + foreach (array_keys($value) as $key) { + if ($key != 'options' && $key != 'criteria') { + $return[$key] = $value[$key]; + } + } + } // iterate through criteria $lastaction = null; diff --git a/grade/grading/form/rubric/styles.css b/grade/grading/form/rubric/styles.css index f46468246df..57616a425ee 100644 --- a/grade/grading/form/rubric/styles.css +++ b/grade/grading/form/rubric/styles.css @@ -107,4 +107,11 @@ .gradingform_rubric .criterion .levels.error { border:1px solid red;} .gradingform_rubric .criterion .description.error, .gradingform_rubric .criterion .levels .level .definition.error, -.gradingform_rubric .criterion .levels .level .score.error {background:#FFDDDD;} \ No newline at end of file +.gradingform_rubric .criterion .levels .level .score.error {background:#FFDDDD;} + +/** + * + */ + +.gradingform_rubric-regrade {padding:10px;background:#FFDDDD;border:1px solid #F00;margin-bottom:10px;} +.gradingform_rubric-error {color:red;font-weight:bold;} diff --git a/mod/assignment/lib.php b/mod/assignment/lib.php index 5bece0de1dd..6ffe5387c82 100644 --- a/mod/assignment/lib.php +++ b/mod/assignment/lib.php @@ -335,7 +335,7 @@ class assignment_base { $grade_str = '
'. get_string("grade").': '.$grade->str_long_grade. '
'; if (!empty($submission) && $controller = get_grading_manager($this->context, 'mod_assignment', 'submission')->get_active_controller()) { $controller->set_grade_range(make_grades_menu($this->assignment->grade)); - echo $controller->render_grade($PAGE, $submission->id, $item, $grade_str); + echo $controller->render_grade($PAGE, $submission->id, $item, $grade_str, has_capability('mod/assignment:grade', $this->context)); } else { echo $grade_str; }