Commit 59766233 authored by James McQuillan's avatar James McQuillan
Browse files

MDL-22999 core_grades: Added ability to configure maximum grade value both...

MDL-22999 core_grades: Added ability to configure maximum grade value both globally and for each graded-activity.
parent 1a727e12
......@@ -67,6 +67,10 @@ if (has_capability('moodle/grade:manage', $systemcontext)
$temp->add(new admin_setting_special_gradeexport());
$temp->add(new admin_setting_special_gradelimiting());
$temp->add(new admin_setting_special_gradepointmax());
$temp->add(new admin_setting_special_gradepointdefault());
}
$ADMIN->add('grades', $temp);
......
......@@ -461,6 +461,8 @@ abstract class moodleform_mod extends moodleform {
$mform->addElement('modgrade', 'scale', get_string('scale'), false);
$mform->disabledIf('scale', 'assessed', 'eq', 0);
$mform->addHelpButton('scale', 'modgrade', 'grades');
$mform->setDefault('scale', $CFG->gradepointdefault);
$mform->addElement('checkbox', 'ratingtime', get_string('ratingtime', 'rating'));
$mform->disabledIf('ratingtime', 'assessed', 'eq', 0);
......@@ -786,7 +788,8 @@ abstract class moodleform_mod extends moodleform {
//if supports grades and grades arent being handled via ratings
if (!$this->_features->rating) {
$mform->addElement('modgrade', 'grade', get_string('grade'));
$mform->setDefault('grade', 100);
$mform->addHelpButton('grade', 'modgrade', 'grades');
$mform->setDefault('grade', $CFG->gradepointdefault);
}
if ($this->_features->advancedgrading
......
......@@ -281,6 +281,12 @@ $string['gradeoutcomes'] = 'Outcomes';
$string['gradeoutcomescourses'] = 'Course outcomes';
$string['gradepass'] = 'Grade to pass';
$string['gradepass_help'] = 'This setting determines the minimum grade required to pass. The value is used in activity and course completion, and in the gradebook, where pass grades are highlighted in green and fail grades in red.';
$string['gradepointdefault'] = 'Grade point default';
$string['gradepointdefault_help'] = 'This setting determines the default value for the grade point value available in an activity.';
$string['gradepointdefault_validateerror'] = 'This setting must be an integer between 1 and the grade point maximum.';
$string['gradepointmax'] = 'Grade point maximum';
$string['gradepointmax_help'] = 'This setting determines the maximum grade point value available in an activity.';
$string['gradepointmax_validateerror'] = 'This setting must be an integer between 1 and 10000.';
$string['gradepreferences'] = 'Grade preferences';
$string['gradepreferenceshelp'] = 'Grade preferences Help';
$string['gradepublishing'] = 'Enable publishing';
......@@ -410,6 +416,15 @@ $string['median'] = 'Median';
$string['min'] = 'Lowest';
$string['missingscale'] = 'Scale must be selected';
$string['mode'] = 'Mode';
$string['modgradeerrorbadpoint'] = 'Invalid Grade Value. This must be an integer between 0 and {$a}';
$string['modgradeerrorbadscale'] = 'Invalid scale selected. Please make sure you select a scale from the selections below.';
$string['modgrade'] = 'Grade';
$string['modgrade_help'] = 'Select the type of grading used for this activity. If "scale" is chosen, you can then choose the scale from the "scale" dropdown. If using "point" grading, you can then enter the maximum grade available for this activity.';
$string['modgrademaxgrade'] = 'Maximum points';
$string['modgradetype'] = 'Type';
$string['modgradetypenone'] = 'None';
$string['modgradetypepoint'] = 'Point';
$string['modgradetypescale'] = 'Scale';
$string['morethanmax'] = 'The grade entered for {$a->itemname} for {$a->username} is more than the maximum allowed';
$string['moveselectedto'] = 'Move selected items to';
$string['movingelement'] = 'Moving {$a}';
......
......@@ -4799,6 +4799,129 @@ class admin_setting_special_gradeexport extends admin_setting_configmulticheckbo
}
/**
* A setting for setting the default grade point value. Must be an integer between 1 and $CFG->gradepointmax.
*
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class admin_setting_special_gradepointdefault extends admin_setting_configtext {
/**
* Config gradepointmax constructor
*
* @param string $name Overidden by "gradepointmax"
* @param string $visiblename Overridden by "gradepointmax" language string.
* @param string $description Overridden by "gradepointmax_help" language string.
* @param string $defaultsetting Not used, overridden by 100.
* @param mixed $paramtype Overridden by PARAM_INT.
* @param int $size Overridden by 5.
*/
public function __construct($name = '', $visiblename = '', $description = '', $defaultsetting = '', $paramtype = PARAM_INT, $size = 5) {
$name = 'gradepointdefault';
$visiblename = get_string('gradepointdefault', 'grades');
$description = get_string('gradepointdefault_help', 'grades');
$defaultsetting = 100;
$paramtype = PARAM_INT;
$size = 5;
parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype, $size);
}
/**
* Validate data before storage
* @param string $data The submitted data
* @return bool|string true if ok, string if error found
*/
public function validate($data) {
global $CFG;
if (((string)(int)$data === (string)$data && $data > 0 && $data <= $CFG->gradepointmax)) {
return true;
} else {
return get_string('gradepointdefault_validateerror', 'grades');
}
}
}
/**
* A setting for setting the maximum grade value. Must be an integer between 1 and 10000.
*
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class admin_setting_special_gradepointmax extends admin_setting_configtext {
/**
* Config gradepointmax constructor
*
* @param string $name Overidden by "gradepointmax"
* @param string $visiblename Overridden by "gradepointmax" language string.
* @param string $description Overridden by "gradepointmax_help" language string.
* @param string $defaultsetting Not used, overridden by 100.
* @param mixed $paramtype Overridden by PARAM_INT.
* @param int $size Overridden by 5.
*/
public function __construct($name = '', $visiblename = '', $description = '', $defaultsetting = '', $paramtype = PARAM_INT, $size = 5) {
$name = 'gradepointmax';
$visiblename = get_string('gradepointmax', 'grades');
$description = get_string('gradepointmax_help', 'grades');
$defaultsetting = 100;
$paramtype = PARAM_INT;
$size = 5;
parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype, $size);
}
/**
* Save the selected setting
*
* @param string $data The selected site
* @return string empty string or error message
*/
public function write_setting($data) {
if ($data === '') {
$data = (int)$this->defaultsetting;
} else {
$data = $data;
}
return parent::write_setting($data);
}
/**
* Validate data before storage
* @param string $data The submitted data
* @return bool|string true if ok, string if error found
*/
public function validate($data) {
if (((string)(int)$data === (string)$data && $data > 0 && $data <= 10000)) {
return true;
} else {
return get_string('gradepointmax_validateerror', 'grades');
}
}
/**
* Return an XHTML string for the setting
* @param array $data Associative array of value=>xx, forced=>xx, adv=>xx
* @param string $query search query to be highlighted
* @return string XHTML to display control
*/
public function output_html($data, $query = '') {
$default = $this->get_defaultsetting();
$attr = array(
'type' => 'text',
'size' => $this->size,
'id' => $this->get_id(),
'name' => $this->get_full_name(),
'value' => s($data),
'maxlength' => '5'
);
$input = html_writer::empty_tag('input', $attr);
$attr = array('class' => 'form-text defaultsnext');
$div = html_writer::tag('div', $input, $attr);
return format_admin_setting($this, $this->visiblename, $div, $this->description, true, '', $default, $query);
}
}
/**
* Grade category settings
*
......
......@@ -28,6 +28,9 @@
global $CFG;
require_once "$CFG->libdir/form/select.php";
require_once("HTML/QuickForm/element.php");
require_once($CFG->dirroot.'/lib/form/group.php');
require_once($CFG->dirroot.'/lib/grade/grade_scale.php');
/**
* Drop down form element to select the grade
......@@ -40,59 +43,240 @@ require_once "$CFG->libdir/form/select.php";
* @copyright 2006 Jamie Pratt <me@jamiep.org>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class MoodleQuickForm_modgrade extends MoodleQuickForm_select{
/** @var bool if true the hides grade */
var $_hidenograde = false;
class MoodleQuickForm_modgrade extends MoodleQuickForm_group{
/**
* Class constructor
* Constructor
*
* @param string $elementName (optional) name attribute
* @param mixed $elementLabel (optional) Label for the drop down
* @param mixed $attributes (optional) Either a typical HTML attribute string or an associative array
* @param mixed $hidenograde (optional) hide grade
* @param string $elementname Element's name
* @param mixed $elementlabel Label(s) for an element
* @param array $options Options to control the element's display. Not used.
* @param mixed $attributes Either a typical HTML attribute string or an associative array
*/
function MoodleQuickForm_modgrade($elementName=null, $elementLabel=null, $attributes=null, $hidenograde=false)
{
HTML_QuickForm_element::HTML_QuickForm_element($elementName, $elementLabel, $attributes, null);
public function MoodleQuickForm_modgrade($elementname = null, $elementlabel = null, $options = array(), $attributes = null) {
$this->HTML_QuickForm_element($elementname, $elementlabel, $attributes);
$this->_persistantFreeze = true;
$this->_appendName = true;
$this->_type = 'modgrade';
$this->_hidenograde = $hidenograde;
}
/**
* Create elements for this group.
*/
public function _createElements() {
global $COURSE, $CFG;
$attributes = $this->getAttributes();
if (is_null($attributes)) {
$attributes = array();
}
$this->_elements = array();
// Create main elements
// We have to create the scale and point elements first, as we need their IDs.
// Grade scale select box.
$scales = get_scales_menu($COURSE->id);
$langscale = get_string('modgradetypescale', 'grades');
$scaleselect = @MoodleQuickForm::createElement('select', 'modgrade_scale', $langscale, $scales, $attributes);
$scaleselect->setHiddenLabel = false;
$scaleselect->_generateId();
$scaleselectid = $scaleselect->getAttribute('id');
// Maximum grade textbox.
$langmaxgrade = get_string('modgrademaxgrade', 'grades');
$maxgrade = @MoodleQuickForm::createElement('text', 'modgrade_point', $langmaxgrade, array());
$maxgrade->setHiddenLabel = false;
$maxgrade->_generateId();
$maxgradeid = $maxgrade->getAttribute('id');
// Grade type select box.
$gradetype = array(
'none' => get_string('modgradetypenone', 'grades'),
'scale' => get_string('modgradetypescale', 'grades'),
'point' => get_string('modgradetypepoint', 'grades'),
);
$langtype = get_string('modgradetype', 'grades');
$typeselect = @MoodleQuickForm::createElement('select', 'modgrade_type', $langtype, $gradetype, $attributes, true);
$typeselect->setHiddenLabel = false;
$typeselect->_generateId();
// Add elements.
// Grade type select box.
$label = html_writer::tag('label', $typeselect->getLabel(), array('for' => $typeselect->getAttribute('id')));
$this->_elements[] = @MoodleQuickForm::createElement('static', 'gradetypelabel', '', '&nbsp;'.$label);
$this->_elements[] = $typeselect;
$this->_elements[] = @MoodleQuickForm::createElement('static', 'gradetypespacer', '', '<br />');
// Grade scale select box.
$label = html_writer::tag('label', $scaleselect->getLabel(), array('for' => $scaleselectid));
$this->_elements[] = @MoodleQuickForm::createElement('static', 'scalelabel', '', $label);
$this->_elements[] = $scaleselect;
$this->_elements[] = @MoodleQuickForm::createElement('static', 'scalespacer', '', '<br />');
// Maximum grade textbox.
$label = html_writer::tag('label', $maxgrade->getLabel(), array('for' => $maxgradeid));
$this->_elements[] = @MoodleQuickForm::createElement('static', 'pointlabel', '', $label);
$this->_elements[] = $maxgrade;
$this->_elements[] = @MoodleQuickForm::createElement('static', 'pointspacer', '', '<br />');
}
/**
* Called by HTML_QuickForm whenever form event is made on this element
* Calculate the output value for the element as a whole.
*
* @param array $submitvalues The incoming values from the form.
* @param bool $notused Not used.
* @return array Return value for the element, formatted like field name => value.
*/
public function exportValue(&$submitvalues, $notused = false) {
global $COURSE;
// Get the values from all the child elements.
$vals = array();
foreach ($this->_elements as $element) {
$thisexport = $element->exportValue($submitvalues[$this->getName()], true);
if (!is_null($thisexport)) {
$vals += $thisexport;
}
}
$type = (isset($vals['modgrade_type'])) ? $vals['modgrade_type'] : 'none';
$point = (isset($vals['modgrade_point'])) ? $vals['modgrade_point'] : null;
$scale = (isset($vals['modgrade_scale'])) ? $vals['modgrade_scale'] : null;
$return = $this->process_value($type, $scale, $point);
return array($this->getName() => $return);
}
/**
* Process the value for the group based on the selected grade type, and the input for the scale and point elements.
*
* @param string $type The value of the grade type select box. Can be 'none', 'scale', or 'point'
* @param string|int $scale The value of the scale select box.
* @param string|int $point The value of the point grade textbox.
* @return int The resulting value
*/
protected function process_value($type='none', $scale=null, $point=null) {
global $COURSE;
$val = 0;
switch ($type) {
case 'point':
if ($this->validate_point($point) === true) {
$val = (int)$point;
}
break;
case 'scale':
if ($this->validate_scale($scale)) {
$val = (int)(-$scale);
}
break;
}
return $val;
}
/**
* Determines whether a given value is a valid scale selection.
*
* @param string|int $val The value to test.
* @return bool Valid or invalid
*/
protected function validate_scale($val) {
global $COURSE;
$scales = get_scales_menu($COURSE->id);
return (!empty($val) && isset($scales[(int)$val])) ? true : false;
}
/**
* Determines whether a given value is a valid point selection.
*
* @param string|int $val The value to test.
* @return bool Valid or invalid
*/
protected function validate_point($val) {
if (empty($val)) {
return false;
}
$maxgrade = (int)get_config('core', 'gradepointmax');
$isintlike = ((string)(int)$val === $val) ? true : false;
return ($isintlike === true && $val > 0 && $val <= $maxgrade) ? true : false;
}
/**
* Called by HTML_QuickForm whenever form event is made on this element.
*
* @param string $event Name of event
* @param mixed $arg event arguments
* @param object $caller calling object
* @return mixed
*/
function onQuickFormEvent($event, $arg, &$caller)
{
global $COURSE, $CFG, $OUTPUT;
public function onQuickFormEvent($event, $arg, &$caller) {
global $COURSE;
switch ($event) {
case 'createElement':
// Need to call superclass first because we want the constructor
// to run.
$result = parent::onQuickFormEvent($event, $arg, $caller);
$strscale = get_string('scale');
$strscales = get_string('scales');
$scales = get_scales_menu($COURSE->id);
foreach ($scales as $i => $scalename) {
$grades[-$i] = $strscale .': '. $scalename;
case 'updateValue':
$value = $this->_findValue($caller->_constantValues);
if (null === $value) {
if ($caller->isSubmitted()) {
$value = $this->_findValue($caller->_submitValues);
} else {
$value = $this->_findValue($caller->_defaultValues);
}
}
if (!$this->_hidenograde) {
$grades[0] = get_string('nograde');
$name = $this->getName();
// Set disable actions.
$caller->disabledIf($name.'[modgrade_scale]', $name.'[modgrade_type]', 'neq', 'scale');
$caller->disabledIf($name.'[modgrade_point]', $name.'[modgrade_type]', 'neq', 'point');
// Set element state for existing data.
if (!empty($this->_elements)) {
if (!empty($value)) {
if ($value < 0) {
$this->_elements[1]->setValue('scale');
$this->_elements[4]->setValue(($value * -1));
} else if ($value > 0) {
$this->_elements[1]->setValue('point');
$this->_elements[7]->setValue($value);
}
} else {
$this->_elements[1]->setValue('none');
$this->_elements[7]->setValue('');
}
}
for ($i=100; $i>=1; $i--) {
$grades[$i] = $i;
// Value Validation.
if ($name && $caller->elementExists($name)) {
$checkmaxgrade = function($val) {
if (isset($val['modgrade_type']) && $val['modgrade_type'] === 'point') {
if (!isset($val['modgrade_point'])) {
return false;
}
return $this->validate_point($val['modgrade_point']);
}
return true;
};
$checkvalidscale = function($val) {
if (isset($val['modgrade_type']) && $val['modgrade_type'] === 'scale') {
if (!isset($val['modgrade_scale'])) {
return false;
}
return $this->validate_scale($val['modgrade_scale']);
}
return true;
};
$maxgradeexceeded = get_string('modgradeerrorbadpoint', 'grades', get_config('core', 'gradepointmax'));
$invalidscale = get_string('modgradeerrorbadscale', 'grades');
$caller->addRule($name, $maxgradeexceeded, 'callback', $checkmaxgrade);
$caller->addRule($name, $invalidscale, 'callback', $checkvalidscale);
}
$this->load($grades);
//TODO: rewrite mod grading support in modforms
return $result;
break;
}
return parent::onQuickFormEvent($event, $arg, $caller);
}
......
This files describes API changes in /mod/* - activity modules,
information provided here is intended especially for developers.
=== 2.7 ===
* modgrade form element has been redesigned and allows setting the maximum grade point higher than 100.
=== 2.6 ===
* Modules using the question bank MUST now declare their use of it with the xxx_supports()
......
......@@ -29,7 +29,7 @@
defined('MOODLE_INTERNAL') || die();
$version = 2014040300.00; // YYYYMMDD = weekly release date of this DEV branch.
$version = 2014040300.01; // YYYYMMDD = weekly release date of this DEV branch.
// RR = release increments - 00 in DEV branches.
// .XX = incremental changes.
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment