--- loncom/interface/lonquickgrades.pm 2011/03/25 01:34:49 1.78
+++ loncom/interface/lonquickgrades.pm 2011/05/27 19:32:10 1.94
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# Quick Student Grades Display
#
-# $Id: lonquickgrades.pm,v 1.78 2011/03/25 01:34:49 www Exp $
+# $Id: lonquickgrades.pm,v 1.94 2011/05/27 19:32:10 www Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -62,7 +62,8 @@ sub real_handler {
$r->send_http_header;
my $showPoints =
- $env{'course.'.$env{'request.course.id'}.'.grading'} eq 'standard';
+ (($env{'course.'.$env{'request.course.id'}.'.grading'} eq 'standard')
+ || ($env{'course.'.$env{'request.course.id'}.'.grading'} eq 'categories'));
my $notshowSPRSlink =
(($env{'course.'.$env{'request.course.id'}.'.grading'} eq 'external')
|| ($env{'course.'.$env{'request.course.id'}.'.grading'} eq 'externalnototals'));
@@ -266,8 +267,12 @@ sub getData {
$totalRight += $score;
$partsCount += $curRes->weight($part);
+ $curRes->{DATA}->{PROB_SCORE} += $score;
+ $curRes->{DATA}->{PROB_WEIGHT} += $curRes->weight($part);
+
if ($curRes->opendate($part) < $now) {
$totalPossible += $curRes->weight($part);
+ $curRes->{DATA}->{PROB_POSSIBLE} += $curRes->weight($part);
}
$totalParts += $curRes->weight($part);
} else {
@@ -459,11 +464,77 @@ sub outputCategories {
&output_category_table($r,$cangrade,$navmap,%categories);
#
if ($cangrade) {
- $r->print(' '.
+ $r->print(&Apache::loncommon::resourcebrowser_javascript().
+ ' '.
' '.
+ ' '.
' '.
'');
}
+#
+# Debug
+#
+# my %data=&dumpdata($navmap);
+# foreach (keys(%data)) {
+# $r->print("\n ".$_.'='.$data{$_});
+# }
+# my @debugarray=('5:1','4:3','1:1','5:5','6:7');
+# $r->print("Array: ".join(',',@debugarray).' ');
+# $r->print("0,0,0: ".join(',',&drop(0,0,0,@debugarray)).' ');
+# $r->print("1,0,0: ".join(',',&drop(1,0,0,@debugarray)).' ');
+# $r->print("0,1,0: ".join(',',&drop(0,1,0,@debugarray)).' ');
+# $r->print("1,1,0: ".join(',',&drop(1,1,0,@debugarray)).' ');
+#
+# $r->print("0,0,2: ".join(',',&drop(0,0,2,@debugarray)).' ');
+# $r->print("1,0,2: ".join(',',&drop(1,0,2,@debugarray)).' ');
+# $r->print("0,1,2: ".join(',',&drop(0,1,2,@debugarray)).' ');
+# $r->print("1,1,2: ".join(',',&drop(1,1,2,@debugarray)).' ');
+#
+# $r->print("0,0,4: ".join(',',&drop(0,0,4,@debugarray)).' ');
+# $r->print("1,0,4: ".join(',',&drop(1,0,4,@debugarray)).' ');
+# $r->print("0,1,4: ".join(',',&drop(0,1,4,@debugarray)).' ');
+# $r->print("1,1,4: ".join(',',&drop(1,1,4,@debugarray)).' ');
+#
+# $r->print("0,0,5: ".join(',',&drop(0,0,5,@debugarray)).' ');
+# $r->print("1,0,5: ".join(',',&drop(1,0,5,@debugarray)).' ');
+# $r->print("0,1,5: ".join(',',&drop(0,1,5,@debugarray)).' ');
+# $r->print("1,1,5: ".join(',',&drop(1,1,5,@debugarray)).' ');
+#
+# $r->print("0,0,7: ".join(',',&drop(0,0,7,@debugarray)).' ');
+# $r->print("1,0,7: ".join(',',&drop(1,0,7,@debugarray)).' ');
+# $r->print("0,1,7: ".join(',',&drop(0,1,7,@debugarray)).' ');
+# $r->print("1,1,7: ".join(',',&drop(1,1,7,@debugarray)).' ');
+
+}
+
+#
+# Get data for all symbs
+#
+
+sub dumpdata {
+ my ($navmap)=@_;
+ my %returndata=();
+
+# Run through the map and get all data
+
+ my $iterator = $navmap->getIterator(undef, undef, undef, 1);
+ my $depth = 1;
+ $iterator->next(); # ignore first BEGIN_MAP
+ my $curRes = $iterator->next();
+
+ while ($depth > 0) {
+ if ($curRes == $iterator->BEGIN_MAP()) {$depth++;}
+ if ($curRes == $iterator->END_MAP()) { $depth--; }
+ if (ref($curRes)) {
+ if ($curRes->is_map()) {
+ $returndata{$curRes->symb()}='folder:'.$curRes->{DATA}->{CHILD_PARTS}.':'.$curRes->{DATA}->{CHILD_ATTEMPTED}.':'.$curRes->{DATA}->{CHILD_CORRECT};
+ } else {
+ $returndata{$curRes->symb()}='res:'.$curRes->{DATA}->{PROB_WEIGHT}.':'.$curRes->{DATA}->{PROB_POSSIBLE}.':'.$curRes->{DATA}->{PROB_SCORE};
+ }
+ }
+ $curRes = $iterator->next();
+ }
+ return %returndata;
}
#
@@ -475,10 +546,13 @@ sub process_category_edits {
unless ($cangrade) { return %categories; }
# First store everything
foreach my $id (split(/\,/,$categories{'order'})) {
+# Set names, types, and weight (there is only one of each per category)
%categories=&set_category_name($cangrade,$id,$env{'form.name_'.$id},%categories);
%categories=&set_category_total($cangrade,$id,$env{'form.totaltype_'.$id},$env{'form.total_'.$id},%categories);
%categories=&set_category_weight($cangrade,$id,$env{'form.weight_'.$id},%categories);
-# More changes here
+ %categories=&set_category_displayachieved($cangrade,$id,$env{'form.displayachieved_'.$id},%categories);
+# Set values for category rules (before names may change)
+ %categories=&set_category_rules($cangrade,$id,%categories);
}
# Now deal with commands
@@ -492,11 +566,13 @@ sub process_category_edits {
} elsif ($cmd=~/^delcat\_(.+)$/) {
%categories=&del_category($1,$cangrade,%categories);
} elsif ($cmd=~/^addcont\_(.+)$/) {
- %categories=&add_category_content($1,$cangrade,$env{'form.addcont_'.$1.'_symb'},%categories);
+ %categories=&add_category_content($1,$cangrade,$env{'form.resourcesymb'},%categories);
} elsif ($cmd=~/^delcont\_(.+)\_\_\_\_\_\_(.+)$/) {
%categories=&del_category_content($1,$cangrade,$2,%categories);
} elsif ($cmd=~/^newrule\_(.+)$/) {
%categories=&add_calculation_rule($1,$cangrade,':',%categories);
+ } elsif ($cmd=~/^delrule\_(.+)\_\_\_\_\_\_(.*)$/) {
+ %categories=&del_calculation_rule($1,$cangrade,$2,%categories);
}
# Move to a new position
my $moveid=$env{'form.storemove'};
@@ -520,9 +596,10 @@ sub output_category_table {
#
my @order=split(/\,/,$categories{'order'});
#
+ my %performance=&dumpdata($navmaps);
my $maxpos=$#order;
for (my $i=0;$i<=$maxpos;$i++) {
- my ($value,$weight)=&output_and_calc_category($r,$cangrade,$navmaps,$order[$i],$i,$maxpos,%categories);
+ my ($value,$weight)=&output_and_calc_category($r,$cangrade,$navmaps,$order[$i],$i,$maxpos,\%performance,1,%categories);
$sum+=$value*$weight;
$total+=$weight;
}
@@ -541,9 +618,10 @@ sub output_category_table_header {
}
$r->print('
'.&mt('Category').' '.
''.&mt('Contents').' '.
- ''.&mt('Calculation').' '.
''.&mt('Total Points').' '.
- ''.&mt('Relative Weight').' ');
+ ''.&mt('Calculation').' '.
+ ''.&mt('Relative Weight').' '.
+ ''.&mt('Achieved').' ');
$r->print(&Apache::loncommon::end_data_table_header_row());
}
@@ -553,16 +631,16 @@ sub output_category_table_header {
#
sub output_and_calc_category {
- my ($r,$cangrade,$navmaps,$id,$currentpos,$maxpos,%categories)=@_;
+ my ($r,$cangrade,$navmaps,$id,$currentpos,$maxpos,$performance,$output,%categories)=@_;
my $value=0;
my $weight=0;
my $iconpath = &Apache::loncommon::lonhttpdurl($r->dir_config('lonIconsURL') . "/");
my %lt=&Apache::lonlocal::texthash(
'up' => 'Move Up',
'dw' => 'Move Down');
- $r->print("\n".&Apache::loncommon::start_data_table_row());
+ if ($output) { $r->print("\n".&Apache::loncommon::start_data_table_row()); }
- if ($cangrade) {
+ if ($output && $cangrade) {
$r->print(<
@@ -589,68 +667,182 @@ ENDMOVE
$r->print('
'.&mt('Delete').' ');
$r->print('
');
- } else {
+ } elsif ($output) {
$r->print('
'.$categories{$id.'_name'}.' ');
}
-# Content
- $r->print('
');
+# Content display and summing up of points
+ my $totalpossible=0;
+ my $totalcorrect=0;
+ my @individual=();
+ if ($output) { $r->print(''); }
foreach my $contentid (split(/\,/,$categories{$id.'_content'})) {
- $r->print('');
- $r->print(&Apache::lonnet::gettitle($contentid));
- if ($cangrade) {
- $r->print(' '.&mt('Delete').' ');
+ my ($type,$possible,$attempted,$correct)=split(/\:/,$$performance{$contentid});
+ $totalpossible+=$possible;
+ $totalcorrect+=$correct;
+ if ($possible>0) { push(@individual,"$possible:$correct"); }
+ if ($output) {
+ $r->print(' ');
+ $r->print(&Apache::lonnet::gettitle($contentid).' ('.$correct.'/'.$possible.')');
+ if ($cangrade) {
+ $r->print(' '.&mt('Delete').' ');
+ }
+ $r->print(' ');
}
- $r->print('');
}
- $r->print(' ');
+ if ($output) {
+ $r->print('');
+ if ($cangrade) {
+ $r->print(' '.&Apache::loncommon::selectresource_link('quickform','addcont_'.$id,&mt('Add Problem or Folder')).' ');
+ }
+ $r->print(''.&mt('Total raw points: [_1]/[_2]',$totalcorrect,$totalpossible).'
');
+ $r->print(' ');
+ }
+# Total
+ if ($output) { $r->print(''); }
if ($cangrade) {
- $r->print(' '.&mt('Add Problem or Sequence').' '.
- &Apache::lonstathelpers::problem_selector('.',undef,1,1,'addcont_'.$id.'_',1,'this.form.cmd.value="addcont_'.$id.'";this.form.submit();'));
+ if ($output) {
+ $r->print(
+ ''.
+ ''.&mt('default').' '.
+ ''.&mt('Type-in value').' '.
+ ' '.
+ ' ');
+ }
+ } else {
+ if ($output) {
+ $r->print(' '.($categories{$id.'_totaltype'} eq 'default'?&mt('default'):$categories{$id.'_total'}));
+ }
}
- $r->print(' ');
+# Adjust total points
+ if ($categories{$id.'_totaltype'} eq 'typein') {
+ $totalpossible=1.*$categories{$id.'_total'};
+ }
+ if ($output) {
+ $r->print(''.&mt('Adjusted raw points: [_1]/[_2]',$totalcorrect,$totalpossible).'
');
+ }
+
+
# Calculation
- $r->print('');
+ if ($output) { $r->print(''); }
foreach my $calcrule (split(/\,/,$categories{$id.'_calculations'})) {
- $r->print('');
+ if ($output) { $r->print(' '); }
my ($code,$value)=split(/\:/,$calcrule);
- $r->print(&pretty_prt_rule($cangrade,$id,$code,$value));
+ if ($output) { $r->print(&pretty_prt_rule($cangrade,$id,$code,$value)); }
if ($cangrade) {
- $r->print(' '.&mt('Delete').' ');
+ if ($output) { $r->print(' '.&mt('Delete').' '); }
}
- $r->print(' ');
+ if ($code eq 'capabove') {
+ if ($totalpossible>0) {
+ if ($totalcorrect/$totalpossible>$value/100.) {
+ $totalcorrect=$totalpossible*$value/100.;
+ }
+ }
+ } elsif ($code eq 'capbelow') {
+ if ($totalpossible>0) {
+ if ($totalcorrect/$totalpossible<$value/100.) {
+ $totalcorrect=$totalpossible*$value/100.;
+ }
+ }
+ } elsif ($code eq 'droplow') {
+ ($totalpossible,$totalcorrect,@individual)=&drop(0,0,$value,@individual);
+ } elsif ($code eq 'drophigh') {
+ ($totalpossible,$totalcorrect,@individual)=&drop(1,0,$value,@individual);
+ } elsif ($code eq 'droplowperc') {
+ ($totalpossible,$totalcorrect,@individual)=&drop(0,1,$value,@individual);
+ } elsif ($code eq 'drophighperc') {
+ ($totalpossible,$totalcorrect,@individual)=&drop(1,1,$value,@individual);
+ }
+ if ($output) { $r->print(''); }
}
- $r->print(' ');
- if ($cangrade) {
- $r->print(' '.&new_calc_rule_form($id));
+# Re-adjust total points if force total
+ if ($categories{$id.'_totaltype'} eq 'typein') {
+ $totalpossible=1.*$categories{$id.'_total'};
}
- $r->print(' ');
-
-# Total
- if ($cangrade) {
- $r->print(''.
- ''.
- ''.&mt('default').' '.
- ''.&mt('Type-in value').' '.
- ' '.
- ' ');
- } else {
- $r->print(''.($categories{$id.'_totaltype'} eq 'default'?&mt('default'):$categories{$id.'_total'}).' ');
+ if ($output) {
+ $r->print(' ');
+ if ($cangrade) { $r->print(' '.&new_calc_rule_form($id)); }
+ $r->print(''.&mt('Calculated points: [_1]/[_2]',$totalcorrect,$totalpossible).'
');
+ $r->print(' ');
}
+
# Weight
if ($cangrade) {
- $r->print(''.
+ if ($output) {
+ $r->print(' '.
' ');
+ }
+ } else {
+ if ($output) {
+ $r->print(''.$categories{$id.'_weight'}.' ');
+ }
+ }
+# Achieved
+ if ($output) { $r->print(''); }
+ if ($cangrade) {
+ if ($output) {
+ $r->print(''.
+ ''.&mt('percent').' '.
+ ''.&mt('points').' '.
+ ' ');
+ }
} else {
- $r->print(' '.$categories{$id.'_weight'}.' ');
+ if ($output) {
+ if ($categories{$id.'_displayachieved'} eq 'percent') {
+ $r->print(&mt('percent'));
+ } else {
+ $r->print(&mt('points'));
+ }
+ }
}
+ if ($output) { $r->print(' '); }
return ($value,$weight);
}
#
+# Drop folders and problems
+#
+
+sub drop {
+ my ($high,$percent,$n,@individual)=@_;
+# Sort assignments by points or percent
+ my @newindividual=sort {
+ my ($pa,$ca)=split(/\:/,$a);
+ my ($pb,$cb)=split(/\:/,$b);
+ if ($percent) {
+ my $perca=0;
+ if ($pa>0) { $perca=$ca/$pa; }
+ my $percb=0;
+ if ($pb>0) { $percb=$cb/$pb; }
+ $perca<=>$percb;
+ } else {
+ $ca<=>$cb;
+ }
+ } @individual;
+# Drop the ones we don't want
+ if ($#newindividual>=$n) {
+ if ($high) {
+ splice(@newindividual,$#newindividual+1-$n,$n);
+ } else {
+ splice(@newindividual,0,$n);
+ }
+ } else {
+ @newindividual=();
+ }
+# Re-calculate how many points possible and achieved
+ my $newpossible=0;
+ my $newcorrect=0;
+ for my $score (@newindividual) {
+ my ($thispossible,$thiscorrect)=(split(/\:/,$score));
+ $newpossible+=$thispossible;
+ $newcorrect+=$thiscorrect;
+ }
+ return ($newpossible,$newcorrect,@newindividual);
+}
+#
# Bottom line with grades
#
@@ -660,7 +852,7 @@ sub bottom_line_category {
if ($cangrade) {
$r->print('
'.&mt('Create New Category').' ');
}
- $r->print('
'.&mt('Current:').$sum.' '.&mt('Total:').$total.' ');
+ $r->print('
'.&mt('Current:').$sum.' '.&mt('Total:').$total.' ');
}
#
@@ -684,27 +876,34 @@ sub make_new_category {
}
$categories{$id.'_weight'}=0;
$categories{$id.'_totaltype'}='default';
+ $categories{$id.'_displayachieved'}='percent';
return %categories;
}
# === Calculation Rule Editing
+sub category_rule_codes {
+ return &Apache::lonlocal::texthash(
+ 'droplowperc' => 'Drop N lowest grade percentage problems/folders',
+ 'drophighperc' => 'Drop N highest grade percentage problems/folderss',
+ 'droplow' => 'Drop N lowest point problems/folders',
+ 'drophigh' => 'Drop N highest point problems/folders',
+ 'capabove' => 'Cap percentage above N percent',
+ 'capbelow' => 'Cap percentage below N percent');
+}
+
sub pretty_prt_rule {
my ($cangrade,$id,$code,$value)=@_;
my $cid=$id.'_'.$code;
- my %lt=&Apache::lonlocal::texthash(
- 'droplow' => 'Drop N lowest grade assignments',
- 'drophigh' => 'Drop N highest grade assignments',
- 'capabove' => 'Cap percentage above N percent',
- 'capbelow' => 'Cap percentage below N percent');
+ my %lt=&category_rule_codes();
my $ret='
';
if ($cangrade) {
$ret.='';
foreach my $calc (''=>'',sort(keys(%lt))) {
$ret.=' '.$lt{$calc}.'';
}
- $ret.=' N= ';
+ $ret.=' N=
';
} else {
$ret.=$lt{$code}.'; N='.$value;
}
@@ -749,6 +948,21 @@ sub del_calculation_rule {
return %categories;
}
+sub set_category_rules {
+ my ($cangrade,$id,%categories)=@_;
+ unless ($cangrade) { return %categories; }
+ my %lt=&category_rule_codes();
+ my @newrules=();
+ foreach my $code ('',(keys(%lt))) {
+ if ($env{'form.sel_'.$id.'_'.$code}) {
+ push(@newrules,$env{'form.sel_'.$id.'_'.$code}.':'.$env{'form.val_'.$id.'_'.$code});
+ }
+ }
+ $categories{$id.'_calculations'}=join(',',sort(@newrules));
+ return %categories;
+}
+
+
# === Category Editing
#
@@ -758,6 +972,7 @@ sub del_calculation_rule {
sub add_category_content {
my ($id,$cangrade,$newcontent,%categories)=@_;
unless ($cangrade) { return %categories; }
+ &Apache::lonnet::logthis("In here $newcontent");
my %newcontent=($newcontent => 1);
foreach my $current (split(/\,/,$categories{$id.'_content'})) {
$newcontent{$current}=1;
@@ -910,6 +1125,15 @@ sub set_category_weight {
return %categories;
}
+sub set_category_displayachieved {
+ my ($cangrade,$id,$value,%categories)=@_;
+ unless ($cangrade) { return %categories; }
+ unless (($value eq 'percent') || ($value eq 'points')) { $value='percent'; }
+ $categories{$id.'_displayachieved'}=$value;
+ return %categories;
+}
+
+
#
# === end category-related
#