Skip to content

Commit

Permalink
Merge branch 'wip-MDL-30270-master' of git://github.com/marinaglancy/…
Browse files Browse the repository at this point in the history
…moodle
  • Loading branch information
Sam Hemelryk committed Nov 21, 2011
2 parents 2b72f6d + a19d105 commit 495bcb0
Show file tree
Hide file tree
Showing 8 changed files with 134 additions and 50 deletions.
4 changes: 2 additions & 2 deletions grade/grading/form/rubric/edit.php
Expand Up @@ -44,8 +44,8 @@
$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, 'allowdraft' => !$controller->has_active_instances()));
$data = $controller->get_definition_for_editing();
$mform = new gradingform_rubric_editrubric(null, array('areaid' => $areaid, 'context' => $context, 'allowdraft' => !$controller->has_active_instances()), 'post', '', array('class' => 'gradingform_rubric_editform'));
$data = $controller->get_definition_for_editing(true);
$returnurl = optional_param('returnurl', $manager->get_management_url(), PARAM_LOCALURL);
$data->returnurl = $returnurl;
$mform->set_data($data);
Expand Down
25 changes: 23 additions & 2 deletions grade/grading/form/rubric/edit_form.php
Expand Up @@ -58,8 +58,8 @@ public function definition() {

// rubric completion status
$choices = array();
$choices[gradingform_controller::DEFINITION_STATUS_DRAFT] = get_string('statusdraft', 'grading');
$choices[gradingform_controller::DEFINITION_STATUS_READY] = get_string('statusready', 'grading');
$choices[gradingform_controller::DEFINITION_STATUS_DRAFT] = html_writer::tag('span', get_string('statusdraft', 'core_grading'), array('class' => 'status draft'));
$choices[gradingform_controller::DEFINITION_STATUS_READY] = html_writer::tag('span', get_string('statusready', 'core_grading'), array('class' => 'status ready'));
$form->addElement('select', 'status', get_string('rubricstatus', 'gradingform_rubric'), $choices)->freeze();

// rubric editor
Expand All @@ -80,6 +80,27 @@ public function definition() {
$form->closeHeaderBefore('buttonar');
}

/**
* Setup the form depending on current values. This method is called after definition(),
* data submission and set_data().
* All form setup that is dependent on form values should go in here.
*
* We remove the element status if there is no current status (i.e. rubric is only being created)
* so the users do not get confused
*/
public function definition_after_data() {
$form = $this->_form;
$el = $form->getElement('status');
if (!$el->getValue()) {
$form->removeElement('status');
} else {
$vals = array_values($el->getValue());
if ($vals[0] == gradingform_controller::DEFINITION_STATUS_READY) {
$this->findButton('saverubric')->setValue(get_string('save', 'gradingform_rubric'));
}
}
}

/**
* Form vlidation.
* If there are errors return array of errors ("fieldname"=>"error message"),
Expand Down
56 changes: 37 additions & 19 deletions grade/grading/form/rubric/js/rubriceditor.js
Expand Up @@ -12,6 +12,10 @@ M.gradingform_rubriceditor.init = function(Y, options) {
}
M.gradingform_rubriceditor.disablealleditors()
Y.on('click', M.gradingform_rubriceditor.clickanywhere, 'body', null)
YUI().use('event-touch', function (Y) {
Y.one('body').on('touchstart', M.gradingform_rubriceditor.clickanywhere);
Y.one('body').on('touchend', M.gradingform_rubriceditor.clickanywhere);
})
M.gradingform_rubriceditor.addhandlers()
};

Expand All @@ -35,6 +39,7 @@ M.gradingform_rubriceditor.disablealleditors = function() {
// it switches this element to edit mode. If rubric button is clicked it does nothing so the 'buttonclick'
// function is invoked
M.gradingform_rubriceditor.clickanywhere = function(e) {
if (e.type == 'touchstart') return
var el = e.target
// if clicked on button - disablecurrenteditor, continue
if (el.get('tagName') == 'INPUT' && el.get('type') == 'submit') {
Expand All @@ -48,7 +53,7 @@ M.gradingform_rubriceditor.clickanywhere = function(e) {
el = el.get('parentNode')
}
if (el) {
if (el.one('textarea').getStyle('display') == 'none') {
if (el.one('textarea').hasClass('hiddenelement')) {
M.gradingform_rubriceditor.disablealleditors()
M.gradingform_rubriceditor.editmode(el, true, focustb)
}
Expand All @@ -61,19 +66,19 @@ M.gradingform_rubriceditor.clickanywhere = function(e) {
// switch the criterion description or level to edit mode or switch back
M.gradingform_rubriceditor.editmode = function(el, editmode, focustb) {
var ta = el.one('textarea')
if (!editmode && ta.getStyle('display') == 'none') return;
if (editmode && ta.getStyle('display') == 'block') return;
var pseudotablink = '<a href="#" class="pseudotablink">&nbsp;</a>',
if (!editmode && ta.hasClass('hiddenelement')) return;
if (editmode && !ta.hasClass('hiddenelement')) return;
var pseudotablink = '<input type="text" size="1" class="pseudotablink"/>',
taplain = ta.get('parentNode').one('.plainvalue'),
tbplain = null,
tb = el.one('input[type=text]')
tb = el.one('.score input[type=text]')
// add 'plainvalue' next to textarea for description/definition and next to input text field for score (if applicable)
if (!taplain) {
ta.get('parentNode').append('<div class="plainvalue"><span class="textvalue">&nbsp;</span>'+pseudotablink+'</div>')
ta.get('parentNode').append('<div class="plainvalue">'+pseudotablink+'<span class="textvalue">&nbsp;</span></div>')
taplain = ta.get('parentNode').one('.plainvalue')
taplain.one('.pseudotablink').on('focus', M.gradingform_rubriceditor.clickanywhere)
if (tb) {
tb.get('parentNode').append('<div class="plainvalue"><span class="textvalue">&nbsp;</span>'+pseudotablink+'</div>')
tb.get('parentNode').append('<span class="plainvalue">'+pseudotablink+'<span class="textvalue">&nbsp;</span></span>')
tbplain = tb.get('parentNode').one('.plainvalue')
tbplain.one('.pseudotablink').on('focus', M.gradingform_rubriceditor.clickanywhere)
}
Expand All @@ -90,20 +95,33 @@ M.gradingform_rubriceditor.editmode = function(el, editmode, focustb) {
}
taplain.one('.textvalue').set('innerHTML', value)
if (tb) tbplain.one('.textvalue').set('innerHTML', tb.get('value'))
// hide/display textarea, textbox and plaintexts
taplain.removeClass('hiddenelement')
ta.addClass('hiddenelement')
if (tb) {
tbplain.removeClass('hiddenelement')
tb.addClass('hiddenelement')
}
} else {
// if we need to show the input fields, set the width/height for textarea so it fills the cell
var width = parseFloat(ta.get('parentNode').getComputedStyle('width')),
height
if (el.hasClass('level')) height = parseFloat(el.getComputedStyle('height')) - parseFloat(el.one('.score').getComputedStyle('height'))
else height = parseFloat(ta.get('parentNode').getComputedStyle('height'))
ta.setStyle('width', Math.max(width,50)+'px').setStyle('height', Math.max(height,20)+'px')
}
// hide/display textarea, textbox and plaintexts
taplain.setStyle('display', editmode ? 'none' : 'block')
ta.setStyle('display', editmode ? 'block' : 'none')
if (tb) {
tbplain.setStyle('display', editmode ? 'none' : 'inline-block')
tb.setStyle('display', editmode ? 'inline-block' : 'none')
try {
var width = parseFloat(ta.get('parentNode').getComputedStyle('width')),
height
if (el.hasClass('level')) height = parseFloat(el.getComputedStyle('height')) - parseFloat(el.one('.score').getComputedStyle('height'))
else height = parseFloat(ta.get('parentNode').getComputedStyle('height'))
ta.setStyle('width', Math.max(width,50)+'px')
ta.setStyle('height', Math.max(height,20)+'px')
}
catch (err) {
// this browser do not support 'computedStyle', leave the default size of the textbox
}
// hide/display textarea, textbox and plaintexts
taplain.addClass('hiddenelement')
ta.removeClass('hiddenelement')
if (tb) {
tbplain.addClass('hiddenelement')
tb.removeClass('hiddenelement')
}
}
// focus the proper input field in edit mode
if (editmode) { if (tb && focustb) tb.focus(); else ta.focus() }
Expand Down
12 changes: 8 additions & 4 deletions grade/grading/form/rubric/lang/en/gradingform_rubric.php
Expand Up @@ -53,19 +53,23 @@
$string['regradeoption1'] = 'Mark for regrade';
$string['restoredfromdraft'] = 'NOTE: The last attempt to grade this person was not saved properly so draft grades have been restored. If you want to cancel these changes use the \'Cancel\' button below.';
$string['rubric'] = 'Rubric';
$string['rubricmapping'] = 'Score to grade mapping rules';
$string['rubricmappingexplained'] = 'The minimum possible score for this rubric is <b>{$a->minscore} points</b> and it will be converted to the minimum grade available in this module (which is zero unless the scale is used).
The maximum score <b>{$a->maxscore} points</b> will be converted to the maximum grade.<br />
Intermediate scores will be converted respectively and rounded to the nearest available grade.<br />
If a scale is used instead of a grade, the score will be converted to the scale elements as if they were consecutive integers.';
$string['rubricnotcompleted'] = 'Please choose something for each criterion';
$string['rubricoptions'] = 'Rubric options';
$string['rubricstatus'] = 'Current rubric status';
$string['save'] = 'Save';
$string['saverubric'] = 'Save rubric and make it ready';
$string['saverubricdraft'] = 'Save as draft';
$string['scorepostfix'] = '{$a} points';
$string['scorepostfix'] = '{$a}points';
$string['showdescriptionstudent'] = 'Display rubric description to those being graded';
$string['showdescriptionteacher'] = 'Display rubric description during evaluation';
$string['showremarksstudent'] = 'Show remarks to those being graded';
$string['showscorestudent'] = 'Display points for each level to those being graded';
$string['showscoreteacher'] = 'Display points for each level during evaluation';
$string['sortlevelsasc'] = 'Sort order for levels:';
$string['sortlevelsasc0'] = 'Descending by number of points';
$string['sortlevelsasc1'] = 'Ascending by number of points';
$string['statusdraft'] = 'Draft';
$string['statusready'] = 'Ready';
$string['sortlevelsasc1'] = 'Ascending by number of points';
46 changes: 30 additions & 16 deletions grade/grading/form/rubric/lib.php
Expand Up @@ -360,9 +360,10 @@ public function get_options() {
/**
* Converts the current definition into an object suitable for the editor form's set_data()
*
* @param boolean $addemptycriterion whether to add an empty criterion if the rubric is completely empty (just being created)
* @return stdClass
*/
public function get_definition_for_editing() {
public function get_definition_for_editing($addemptycriterion = false) {

$definition = $this->get_definition();
$properties = new stdClass();
Expand All @@ -378,6 +379,8 @@ public function get_definition_for_editing() {
$properties->rubric = array('criteria' => array(), 'options' => $this->get_options());
if (!empty($definition->rubric_criteria)) {
$properties->rubric['criteria'] = $definition->rubric_criteria;
} else if (!$definition && $addemptycriterion) {
$properties->rubric['criteria'] = array('addcriterion' => 1);
}

return $properties;
Expand Down Expand Up @@ -481,7 +484,8 @@ public function render_preview(moodle_page $page) {
$output = $this->get_renderer($page);
$criteria = $this->definition->rubric_criteria;
$options = $this->get_options();
$rubric = $output->display_rubric($criteria, $options, self::DISPLAY_PREVIEW, 'rubric');
$rubric = $output->display_rubric_mapping_explained($this->get_min_max_score());
$rubric .= $output->display_rubric($criteria, $options, self::DISPLAY_PREVIEW, 'rubric');

return $rubric;
}
Expand Down Expand Up @@ -590,6 +594,28 @@ public static function sql_search_where($token) {

return array($subsql, $params);
}

/**
* Calculates and returns the possible minimum and maximum score (in points) for this rubric
*
* @return array
*/
public function get_min_max_score() {
if (!$this->is_form_available()) {
return null;
}
$returnvalue = array('minscore' => 0, 'maxscore' => 0);
foreach ($this->get_definition()->rubric_criteria as $id => $criterion) {
$scores = array();
foreach ($criterion['levels'] as $level) {
$scores[] = $level['score'];
}
sort($scores);
$returnvalue['minscore'] += $scores[0];
$returnvalue['maxscore'] += $scores[sizeof($scores)-1];
}
return $returnvalue;
}
}

/**
Expand Down Expand Up @@ -717,19 +743,7 @@ public function get_grade() {
global $DB, $USER;
$grade = $this->get_rubric_filling();

$minscore = 0;
$maxscore = 0;
foreach ($this->get_controller()->get_definition()->rubric_criteria as $id => $criterion) {
$scores = array();
foreach ($criterion['levels'] as $level) {
$scores[] = $level['score'];
}
sort($scores);
$minscore += $scores[0];
$maxscore += $scores[sizeof($scores)-1];
}

if ($maxscore <= $minscore) {
if (!($scores = $this->get_controller()->get_min_max_score()) || $scores['maxscore'] <= $scores['minscore']) {
return -1;
}

Expand All @@ -745,7 +759,7 @@ public function get_grade() {
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
return round(($curscore-$scores['minscore'])/($scores['maxscore']-$scores['minscore'])*($maxgrade-$mingrade), 0) + $mingrade;
}

/**
Expand Down
22 changes: 20 additions & 2 deletions grade/grading/form/rubric/renderer.php
Expand Up @@ -164,7 +164,7 @@ public function level_template($mode, $options, $elementname = '{NAME}', $criter
$leveltemplate .= html_writer::start_tag('div', array('class' => 'level-wrapper'));
if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FULL) {
$definition = html_writer::tag('textarea', htmlspecialchars($level['definition']), array('name' => '{NAME}[criteria][{CRITERION-id}][levels][{LEVEL-id}][definition]', 'cols' => '10', 'rows' => '4'));
$score = html_writer::empty_tag('input', array('type' => 'text', 'name' => '{NAME}[criteria][{CRITERION-id}][levels][{LEVEL-id}][score]', 'size' => '4', 'value' => $level['score']));
$score = html_writer::empty_tag('input', array('type' => 'text', 'name' => '{NAME}[criteria][{CRITERION-id}][levels][{LEVEL-id}][score]', 'size' => '3', 'value' => $level['score']));
} else {
if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FROZEN) {
$leveltemplate .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => '{NAME}[criteria][{CRITERION-id}][levels][{LEVEL-id}][definition]', 'value' => $level['definition']));
Expand All @@ -181,7 +181,7 @@ public function level_template($mode, $options, $elementname = '{NAME}', $criter
if ($mode == gradingform_rubric_controller::DISPLAY_EVAL_FROZEN && $level['checked']) {
$leveltemplate .= 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}-criteria-{CRITERION-id}-levels-{LEVEL-id}-score'));
$score = html_writer::tag('span', $score, array('id' => '{NAME}-criteria-{CRITERION-id}-levels-{LEVEL-id}-score', 'class' => 'scorevalue'));
$definitionclass = 'definition';
if (isset($level['error_definition'])) {
$definitionclass .= ' error';
Expand Down Expand Up @@ -453,4 +453,22 @@ public function display_regrade_confirmation($elementname, $changelevel, $value)
$html .= html_writer::end_tag('div');
return $html;
}

/**
* Generates and returns HTML code to display information box about how rubric score is converted to the grade
*
* @param array $scores
* @return string
*/
public function display_rubric_mapping_explained($scores) {
$html = '';
if (!$scores) {
return $html;
}
$html .= $this->box(
html_writer::tag('h4', get_string('rubricmapping', 'gradingform_rubric')).
html_writer::tag('div', get_string('rubricmappingexplained', 'gradingform_rubric', (object)$scores))
, 'generalbox rubricmappingexplained');
return $html;
}
}
8 changes: 4 additions & 4 deletions grade/grading/form/rubric/rubriceditor.php
Expand Up @@ -184,14 +184,14 @@ protected function prepare_data($value = null, $withvalidation = false) {
// when adding new criterion copy the number of levels and their scores from the last criterion
if (!empty($value['criteria'][$lastid]['levels'])) {
foreach ($value['criteria'][$lastid]['levels'] as $lastlevel) {
$criterion['levels']['NEWID'+($i++)]['score'] = $lastlevel['score'];
$criterion['levels']['NEWID'.($i++)]['score'] = $lastlevel['score'];
}
} else {
$criterion['levels']['NEWID'+($i++)]['score'] = 0;
$criterion['levels']['NEWID'.($i++)]['score'] = 0;
}
// add more levels so there are at least 3 in the new criterion. Increment by 1 the score for each next one
for ($i; $i<3; $i++) {
$criterion['levels']['NEWID'+$i]['score'] = $criterion['levels']['NEWID'+($i-1)]['score'] + 1;
for ($i=$i; $i<3; $i++) {
$criterion['levels']['NEWID'.$i]['score'] = $criterion['levels']['NEWID'.($i-1)]['score'] + 1;
}
// set other necessary fields (definition) for the levels in the new criterion
foreach (array_keys($criterion['levels']) as $i) {
Expand Down
11 changes: 10 additions & 1 deletion grade/grading/form/rubric/styles.css
Expand Up @@ -45,6 +45,10 @@
*/

.gradingform_rubric_editform .status {font-weight:normal;text-transform:uppercase;font-size:60%;padding:0.25em;border:1px solid #EEE;-moz-border-radius:5px;}
.gradingform_rubric_editform .status.ready {background-color:#e7f1c3;border-color:#AAEEAA;}
.gradingform_rubric_editform .status.draft {background-color:#f3f2aa;border-color:#EEEE22;}

.gradingform_rubric.editor .criterion .controls,
.gradingform_rubric .criterion .description,
.gradingform_rubric .criterion .levels,
Expand Down Expand Up @@ -75,7 +79,8 @@
.gradingform_rubric .plainvalue.empty {font-style: italic; color: #AAA;}

.gradingform_rubric.editor .criterion .levels .level .delete {position:absolute;right:0;bottom:0;}
.gradingform_rubric .criterion .levels .level .score {font-style:italic;color:#575;font-weight: bold;margin-top:5px;}
.gradingform_rubric .criterion .levels .level .score {font-style:italic;color:#575;font-weight: bold;margin-top:5px;nowrap:nowrap;}
.gradingform_rubric .criterion .levels .level .score .scorevalue {padding-right:5px;}

/* Make invisible the buttons 'Move up' for the first criterion and 'Move down' for the last, because those buttons will make no change */
.gradingform_rubric.editor .criterion.first .controls .moveup input,
Expand Down Expand Up @@ -110,6 +115,10 @@
.gradingform_rubric .criterion .levels .level .definition.error,
.gradingform_rubric .criterion .levels .level .score.error {background:#FFDDDD;}

/* special classes for elements created by rubriceditor.js */
.gradingform_rubric.editor .hiddenelement {display:none;}
.gradingform_rubric.editor .pseudotablink {background-color:transparent;border:0px solid;height:1px;width:1px;color:transparent;padding:0;margin:0;position:relative;float:right;}

/**
*
*/
Expand Down

0 comments on commit 495bcb0

Please sign in to comment.