'.&mt('LON-CAPA is unable to produce your Excel spreadsheet because your selections will result in more than 255 columns. Excel allows only 255 columns in a spreadsheet.').'
'.$/.
+ ''
+ .&mt('Compiling Excel spreadsheet for [quant,_1,student]...',$studentcount)
+ ."
\n"
+ );
$r->rflush();
#
# Initialize progress window
%prog_state=&Apache::lonhtmlcommon::Create_PrgWin
($r,'Excel File Compilation Status',
- 'Excel File Compilation Progress', $studentcount);
+ 'Excel File Compilation Progress', $studentcount,
+ 'inline',undef,'Statistics','stats_status');
#
+ &Apache::lonhtmlcommon::Update_PrgWin($r,\%prog_state,
+ 'Processing first student');
return;
}
sub excel_outputstudent {
my ($r,$student) = @_;
- return if ($request_aborted);
- return if (! defined($excel_sheet));
+ if ($request_aborted || ! defined($navmap) || ! defined($excel_sheet)) {
+ return;
+ }
$cols_output=0;
#
# Write out student data
my @to_show = &get_student_fields_to_show();
foreach my $field (@to_show) {
- $excel_sheet->write($rows_output,$cols_output++,$student->{$field});
+ my $value = $student->{$field};
+ if ($field eq 'comments') {
+ $value = &Apache::lonmsgdisplay::retrieve_instructor_comments
+ ($student->{'username'},$student->{'domain'});
+ }
+ $excel_sheet->write($rows_output,$cols_output++,$value);
}
#
# Get student assessment data
@@ -1061,38 +1485,93 @@ sub excel_outputstudent {
my @tmp = &Apache::loncoursedata::get_current_state($student->{'username'},
$student->{'domain'},
undef,
- $ENV{'request.course.id'});
+ $env{'request.course.id'});
if ((scalar @tmp > 0) && ($tmp[0] !~ /^error:/)) {
%StudentsData = @tmp;
}
#
# Write out sequence scores and totals data
- foreach my $seq (&Apache::lonstatistics::Sequences_with_Assess()) {
+ my %total_cell_translation;
+ my %maximum_cell_translation;
+ foreach my $seq (@sequences) {
+ my $symb = $seq->symb;
+ $cols_output = $formula_data{$symb}->{'Excel:startcol'};
+ # Keep track of cells to translate in total cell
+ $total_cell_translation{$formula_data{$symb}->{'Excel:scorecell'}} =
+ &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell
+ ($rows_output,$formula_data{$symb}->{'Excel:scorecol'});
+ # and maximum cell
+ $maximum_cell_translation{$formula_data{$symb}->{'Excel:maxcell'}} =
+ &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell
+ ($rows_output,$formula_data{$symb}->{'Excel:maxcol'});
+ #
my ($performance,$performance_length,$score,$seq_max,$rawdata);
- if ($base eq 'tries') {
+ if ($chosen_output->{'tries'} || $chosen_output->{'correct'}){
($performance,$performance_length,$score,$seq_max,$rawdata) =
- &StudentTriesOnSequence($student,\%StudentsData,
- $seq,'no');
+ &student_tries_on_sequence($student,\%StudentsData,
+ $navmap,$seq,'no');
} else {
($performance,$performance_length,$score,$seq_max,$rawdata) =
- &StudentPerformanceOnSequence($student,\%StudentsData,
- $seq,'no');
+ &student_performance_on_sequence($student,\%StudentsData,
+ $navmap,$seq,'no',
+ $chosen_output->{ignore_weight});
+ }
+ if ($chosen_output->{'every_problem'}) {
+ if ($chosen_output->{'correct'}) {
+ # only indiciate if each item is correct or not
+ foreach my $value (@$rawdata) {
+ # positive means correct, 0 or negative means
+ # incorrect
+ $value = $value > 0 ? 1 : 0;
+ $excel_sheet->write($rows_output,$cols_output++,$value);
+ }
+ } else {
+ foreach my $value (@$rawdata) {
+ if ($score eq ' ' || !defined($value)) {
+ $cols_output++;
+ } else {
+ $excel_sheet->write($rows_output,$cols_output++,
+ $value);
+ }
+ }
+ }
}
- if ($data eq 'tries' || $data eq 'scores') {
- foreach my $value (@$rawdata) {
- $excel_sheet->write($rows_output,$cols_output++,$value);
+ if ($chosen_output->{'sequence_sum'} &&
+ $chosen_output->{'every_problem'}) {
+ # Write a formula for the sum of this sequence
+ my %replaceCells=
+ ('^'.$formula_data{$symb}->{'Excel:startcell'}.':'.$formula_data{$symb}->{'Excel:endcell'}.'$'
+ =>
+ &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell($rows_output,$formula_data{$symb}->{'Excel:startcol'}).':'.
+ &Spreadsheet::WriteExcel::Utility::xl_rowcol_to_cell($rows_output,$formula_data{$symb}->{'Excel:endcol'})
+ );
+ # The undef is for the format
+ $excel_sheet->repeat_formula($rows_output,$cols_output++,
+ $formula_data{$symb}->{'Excel:sum'},undef,
+ %replaceCells, %replaceCells);
+ } elsif ($chosen_output->{'sequence_sum'}) {
+ if ($score eq ' ') {
+ $cols_output++;
+ } else {
+ $excel_sheet->write($rows_output,$cols_output++,$score);
}
- $excel_sheet->write($rows_output,$cols_output++,$score);
- $excel_sheet->write($rows_output,$cols_output++,$seq_max);
- } elsif ($data eq 'sum and total' || $data eq 'sum only' ||
- $data eq 'parts correct' || $data eq 'parts correct total') {
- $excel_sheet->write($rows_output,$cols_output++,$score);
}
- if ($data eq 'sum and total' || $data eq 'parts correct total') {
+ if ($chosen_output->{'sequence_max'}) {
$excel_sheet->write($rows_output,$cols_output++,$seq_max);
}
}
#
+ if ($chosen_output->{'grand_total'}) {
+ $excel_sheet->repeat_formula($rows_output,$cols_output++,
+ $total_formula,undef,
+ %total_cell_translation);
+ }
+ if ($chosen_output->{'grand_maximum'}) {
+ $excel_sheet->repeat_formula($rows_output,$cols_output++,
+ $maximum_formula,undef,
+ %maximum_cell_translation);
+ }
+ #
# Bookkeeping
$rows_output++;
$cols_output=0;
@@ -1104,22 +1583,22 @@ sub excel_outputstudent {
sub excel_finish {
my ($r) = @_;
- return if ($request_aborted);
- return if (! defined($excel_sheet));
+ if ($request_aborted || ! defined($navmap) || ! defined($excel_sheet)) {
+ &excel_cleanup();
+ return;
+ }
#
# Write the excel file
$excel_workbook->close();
- my $c = $r->connection();
- #
- return if($c->aborted());
#
# Close the progress window
&Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state);
#
# Tell the user where to get their excel file
$r->print('Unable to Complete Request
@@ -1168,89 +1664,102 @@ END
$request_aborted = 1;
}
return if ($request_aborted);
-
+ #
+ # Initialize progress window
+ my $studentcount = scalar(@Apache::lonstatistics::Students);
+ %prog_state=&Apache::lonhtmlcommon::Create_PrgWin
+ ($r,'CSV File Compilation Status',
+ 'CSV File Compilation Progress', $studentcount,
+ 'inline',undef,'Statistics','stats_status');
#
# Open a file
- $filename = '/prtspool/'.
- $ENV{'user.name'}.'_'.$ENV{'user.domain'}.'_'.
- time.'_'.rand(1000000000).'.csv';
- unless ($outputfile = Apache::File->new('>/home/httpd'.$filename)) {
- $r->log_error("Couldn't open $filename for output $!");
- $r->print("Problems occured in writing the csv file. ".
- "This error has been logged. ".
- "Please alert your LON-CAPA administrator.");
- $outputfile = undef;
- }
+ ($outputfile,$filename) = &Apache::loncommon::create_text_file($r,'csv');
+ if (! defined($outputfile)) { return ''; }
#
# Datestamp
- my $description = $ENV{'course.'.$ENV{'request.course.id'}.'.description'};
+ my $description = $env{'course.'.$env{'request.course.id'}.'.description'};
print $outputfile '"'.&Apache::loncommon::csv_translate($description).'",'.
'"'.&Apache::loncommon::csv_translate(scalar(localtime(time))).'"'.
"\n";
+ print $outputfile '"'.
+ &Apache::loncommon::csv_translate
+ (&Apache::lonstatistics::section_and_enrollment_description()).
+ '"'."\n";
+ foreach my $item ('shortdesc','non_html_notes') {
+ next if (! exists($chosen_output->{$item}));
+ print $outputfile
+ '"'.&Apache::loncommon::csv_translate($chosen_output->{$item}).'"'.
+ "\n";
+ }
#
# Print out the headings
- my $Str = '';
- my $Str2 = undef;
+ my $sequence_row = '';
+ my $resource_row = undef;
foreach my $field (&get_student_fields_to_show()) {
- if ($data eq 'sum only') {
- $Str .= '"'.&Apache::loncommon::csv_translate($field).'",';
- } elsif ($data eq 'sum and total' || $data eq 'parts correct total') {
- $Str .= '"",'; # first row empty on the student fields
- $Str2 .= '"'.&Apache::loncommon::csv_translate($field).'",';
- } elsif ($data eq 'scores' || $data eq 'tries' ||
- $data eq 'parts correct') {
- $Str .= '"",';
- $Str2 .= '"'.&Apache::loncommon::csv_translate($field).'",';
- }
- }
- foreach my $seq (&Apache::lonstatistics::Sequences_with_Assess()) {
- if ($data eq 'sum only' || $data eq 'parts correct') {
- $Str .= '"'.&Apache::loncommon::csv_translate($seq->{'title'}).
- '",';
- } elsif ($data eq 'sum and total' || $data eq 'parts correct total') {
- $Str .= '"'.&Apache::loncommon::csv_translate($seq->{'title'}).
- '","",';
- $Str2 .= '"score","total possible",';
- } elsif ($data eq 'scores' || $data eq 'tries') {
- $Str .= '"'.&Apache::loncommon::csv_translate($seq->{'title'}).
- '",';
- $Str .= '"",'x($seq->{'num_assess_parts'}-1+2);
- foreach my $res (@{$seq->{'contents'}}) {
- next if ($res->{'type'} ne 'assessment');
- foreach my $part (@{$res->{'parts'}}) {
- $Str2 .= '"'.&Apache::loncommon::csv_translate($res->{'title'}.', Part '.$part).'",';
+ $sequence_row .='"",';
+ $resource_row .= '"'.&Apache::loncommon::csv_translate($field).'",';
+ }
+ foreach my $seq (@sequences) {
+ $sequence_row .= '"'.
+ &Apache::loncommon::csv_translate($seq->compTitle).'",';
+ my $count = 0;
+ if ($chosen_output->{'every_problem'}) {
+ foreach my $res (&get_resources($navmap,$seq)) {
+ if (scalar(@{$res->parts}) < 1) {
+ next;
+ }
+ foreach my $part (@{$res->parts}) {
+ $resource_row .= '"'.
+ &Apache::loncommon::csv_translate
+ ($res->compTitle.', Part '.$res->part_display($part)).'",';
+ $count++;
}
}
- $Str2 .= '"score","total possible",';
}
- }
- chop($Str);
- $Str .= "\n";
- print $outputfile $Str;
- if (defined($Str2)) {
- chop($Str2);
- $Str2 .= "\n";
- print $outputfile $Str2;
- }
- #
- # Initialize progress window
- my $studentcount = scalar(@Apache::lonstatistics::Students);
- %prog_state=&Apache::lonhtmlcommon::Create_PrgWin
- ($r,'CSV File Compilation Status',
- 'CSV File Compilation Progress', $studentcount);
+ $sequence_row.='"",'x$count;
+ if ($chosen_output->{'sequence_sum'}) {
+ if($chosen_output->{'correct'}) {
+ $resource_row .= '"'.&mt('sum').'",';
+ } else {
+ $resource_row .= '"'.&mt('score').'",';
+ }
+ }
+ if ($chosen_output->{'sequence_max'}) {
+ $sequence_row.= '"",';
+ $resource_row .= '"'.&mt('maximum possible').'",';
+ }
+ }
+ if ($chosen_output->{'grand_total'}) {
+ $sequence_row.= '"",';
+ $resource_row.= '"'.&mt('Total').'",';
+ }
+ if ($chosen_output->{'grand_maximum'}) {
+ $sequence_row.= '"",';
+ $resource_row.= '"'.&mt('Maximum').'",';
+ }
+ chomp($sequence_row);
+ chomp($resource_row);
+ print $outputfile $sequence_row."\n";
+ print $outputfile $resource_row."\n";
return;
}
sub csv_outputstudent {
my ($r,$student) = @_;
- return if ($request_aborted);
- return if (! defined($outputfile));
+ if ($request_aborted || ! defined($navmap) || ! defined($outputfile)) {
+ return;
+ }
my $Str = '';
#
# Output student fields
my @to_show = &get_student_fields_to_show();
foreach my $field (@to_show) {
- $Str .= '"'.&Apache::loncommon::csv_translate($student->{$field}).'",';
+ my $value = $student->{$field};
+ if ($field eq 'comments') {
+ $value = &Apache::lonmsgdisplay::retrieve_instructor_comments
+ ($student->{'username'},$student->{'domain'});
+ }
+ $Str .= '"'.&Apache::loncommon::csv_translate($value).'",';
}
#
# Get student assessment data
@@ -1258,30 +1767,55 @@ sub csv_outputstudent {
my @tmp = &Apache::loncoursedata::get_current_state($student->{'username'},
$student->{'domain'},
undef,
- $ENV{'request.course.id'});
+ $env{'request.course.id'});
if ((scalar @tmp > 0) && ($tmp[0] !~ /^error:/)) {
%StudentsData = @tmp;
}
#
# Output performance data
- foreach my $seq (&Apache::lonstatistics::Sequences_with_Assess()) {
+ my $total = 0;
+ my $maximum = 0;
+ foreach my $seq (@sequences) {
my ($performance,$performance_length,$score,$seq_max,$rawdata);
- if ($base eq 'tries') {
+ if ($chosen_output->{'tries'}){
($performance,$performance_length,$score,$seq_max,$rawdata) =
- &StudentTriesOnSequence($student,\%StudentsData,
- $seq,'no');
+ &student_tries_on_sequence($student,\%StudentsData,
+ $navmap,$seq,'no');
} else {
($performance,$performance_length,$score,$seq_max,$rawdata) =
- &StudentPerformanceOnSequence($student,\%StudentsData,
- $seq,'no');
+ &student_performance_on_sequence($student,\%StudentsData,
+ $navmap,$seq,'no',
+ $chosen_output->{ignore_weight});
+ }
+ if ($chosen_output->{'every_problem'}) {
+ if ($chosen_output->{'correct'}) {
+ $score = 0;
+ # Deal with number of parts correct data
+ $Str .= '"'.join('","',( map { if ($_>0) {
+ $score += 1;
+ 1;
+ } else {
+ 0;
+ }
+ } @$rawdata)).'",';
+ } else {
+ $Str .= '"'.join('","',(@$rawdata)).'",';
+ }
}
- if ($data eq 'sum only' || $data eq 'parts correct') {
+ if ($chosen_output->{'sequence_sum'}) {
$Str .= '"'.$score.'",';
- } elsif ($data eq 'sum and total' || $data eq 'parts correct total') {
- $Str .= '"'.$score.'","'.$seq_max.'",';
- } elsif ($data eq 'scores' || $data eq 'tries') {
- $Str .= '"'.join('","',(@$rawdata,$score,$seq_max)).'",';
+ }
+ if ($chosen_output->{'sequence_max'}) {
+ $Str .= '"'.$seq_max.'",';
}
+ $total+=$score;
+ $maximum += $seq_max;
+ }
+ if ($chosen_output->{'grand_total'}) {
+ $Str .= '"'.$total.'",';
+ }
+ if ($chosen_output->{'grand_maximum'}) {
+ $Str .= '"'.$maximum.'",';
}
chop($Str);
$Str .= "\n";
@@ -1294,26 +1828,38 @@ sub csv_outputstudent {
sub csv_finish {
my ($r) = @_;
- return if ($request_aborted);
- return if (! defined($outputfile));
+ if ($request_aborted || ! defined($navmap) || ! defined($outputfile)) {
+ &csv_cleanup();
+ return;
+ }
close($outputfile);
#
- my $c = $r->connection();
- return if ($c->aborted());
- #
# Close the progress window
&Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state);
#
# Tell the user where to get their csv file
$r->print('
'.
- 'Your csv file.'."\n");
+ ''.&mt('Your CSV file.').''."\n");
$r->rflush();
+ &csv_cleanup();
return;
}
}
+# This function will return an HTML string including a star, with
+# a mouseover popup showing the "real" value. An optional second
+# argument lets you show something other than a star.
+sub show_star {
+ my $popup = shift;
+ my $symbol = shift || '*';
+ # Escape the popup for JS.
+ $popup =~ s/([^-a-zA-Z0-9:;,._ ()|!\/?=&*])/'\\' . sprintf("%lo", ord($1))/ge;
+
+ return "";
+}
+
#######################################################
#######################################################
@@ -1339,96 +1885,148 @@ Inputs:
#######################################################
#######################################################
-sub StudentTriesOnSequence {
- my ($student,$studentdata,$seq,$links) = @_;
+sub student_tries_on_sequence {
+ my ($student,$studentdata,$navmap,$seq,$links) = @_;
$links = 'no' if (! defined($links));
my $Str = '';
my ($sum,$max) = (0,0);
my $performance_length = 0;
my @TriesData = ();
my $tries;
- foreach my $resource (@{$seq->{'contents'}}) {
- next if ($resource->{'type'} ne 'assessment');
- my $resource_data = $studentdata->{$resource->{'symb'}};
+ my $hasdata = 0; # flag - true if the student has any data on the sequence
+ foreach my $resource (&get_resources($navmap,$seq)) {
+ my $resource_data = $studentdata->{$resource->symb};
my $value = '';
- foreach my $partnum (@{$resource->{'parts'}}) {
+ foreach my $partnum (@{$resource->parts()}) {
$tries = undef;
$max++;
$performance_length++;
my $symbol = ' '; # default to space
#
+ my $awarded = 0;
+ if (exists($resource_data->{'resource.'.$partnum.'.awarded'})) {
+ $awarded = $resource_data->{'resource.'.$partnum.'.awarded'};
+ $awarded = 0 if (! $awarded);
+ }
+ #
+ my $status = '';
if (exists($resource_data->{'resource.'.$partnum.'.solved'})) {
- my $status = $resource_data->{'resource.'.$partnum.'.solved'};
- if ($status eq 'correct_by_override') {
- $symbol = '+';
- $sum++;
- } elsif ($status eq 'incorrect_by_override') {
- $symbol = '-';
- } elsif ($status eq 'ungraded_attempted') {
- $symbol = '#';
- } elsif ($status eq 'incorrect_attempted') {
- $symbol = '.';
- } elsif ($status eq 'excused') {
+ $status = $resource_data->{'resource.'.$partnum.'.solved'};
+ }
+ #
+ my $tries = 0;
+ if(exists($resource_data->{'resource.'.$partnum.'.tries'})) {
+ $tries = $resource_data->{'resource.'.$partnum.'.tries'};
+ $hasdata =1;
+ }
+ #
+ if ($awarded > 0) {
+ # The student has gotten the problem correct to some degree
+ if ($status eq 'excused') {
$symbol = 'x';
$max--;
- } elsif ($status eq 'correct_by_student' &&
- exists($resource_data->{'resource.'.$partnum.'.tries'})){
- $tries = $resource_data->{'resource.'.$partnum.'.tries'};
+ } elsif ($status eq 'correct_by_override' && !$resource->is_task()) {
+ $symbol = '+';
+ $sum++;
+ } elsif ($tries > 0) {
if ($tries > 9) {
- $symbol = '*';
- } elsif ($tries > 0) {
- $symbol = $tries;
+ $symbol = show_star($tries);
} else {
- $symbol = ' ';
+ $symbol = $tries;
}
$sum++;
- } elsif (exists($resource_data->{'resource.'.
- $partnum.'.tries'})){
- $symbol = '.';
} else {
- $symbol = ' ';
+ $symbol = '+';
+ $sum++;
}
} else {
- # Unsolved. Did they try?
- if (exists($resource_data->{'resource.'.$partnum.'.tries'})){
+ # The student has the problem incorrect or it is ungraded
+ if ($status eq 'excused') {
+ $symbol = 'x';
+ $max--;
+ } elsif ($status eq 'incorrect_by_override') {
+ $symbol = '-';
+ } elsif ($status eq 'ungraded_attempted') {
+ $symbol = 'u';
+ } elsif ($status eq 'incorrect_attempted' ||
+ $tries > 0) {
$symbol = '.';
} else {
- $symbol = ' ';
+ # Problem is wrong and has not been attempted.
+ $symbol=' ';
}
}
#
if (! defined($tries)) {
- $tries = $symbol;
+ $tries = 0;
+ }
+ if ($status =~ /^(incorrect|ungraded)/) {
+ # Bug 3390: show '-' for tries on incorrect problems
+ # (csv & excel only)
+ push(@TriesData,-$tries);
+ } else {
+ push (@TriesData,$tries);
}
- push (@TriesData,$tries);
#
if ( ($links eq 'yes' && $symbol ne ' ') ||
($links eq 'all')) {
- if (length($symbol) > 1) {
- &Apache::lonnet::logthis('length of symbol "'.$symbol.'" > 1');
- }
- $symbol = ''.$symbol.'';
+ '&userdom='.$student->{'domain'}.
+ '&command=submission';
+ $symbol = &link($symbol, $link);
}
$value .= $symbol;
}
$Str .= $value;
}
- if ($seq->{'randompick'}) {
- $max = $seq->{'randompick'};
+ if ($seq->randompick()) {
+ $max = $seq->randompick();
+ }
+ if (! $hasdata && $sum == 0) {
+ $sum = ' ';
}
return ($Str,$performance_length,$sum,$max,\@TriesData);
}
+=pod
+
+=item &link
+
+Inputs:
+
+=over 4
+
+=item $text
+
+=item $target
+
+=back
+
+Takes the text and creates a link to the $text that honors
+the value of 'new window' if clicked on, but uses a real
+'href' so middle and right clicks still work.
+
+$target and $text are assumed to be already correctly escaped; i.e., it
+can be dumped out directly into the output stream as-is.
+
+=cut
+
+sub link {
+ my ($text,$target) = @_;
+ return
+ "$text";
+}
+
#######################################################
#######################################################
=pod
-=item &StudentPerformanceOnSequence()
+=item &student_performance_on_sequence
Inputs:
@@ -1448,8 +2046,8 @@ Inputs:
#######################################################
#######################################################
-sub StudentPerformanceOnSequence {
- my ($student,$studentdata,$seq,$links) = @_;
+sub student_performance_on_sequence {
+ my ($student,$studentdata,$navmap,$seq,$links,$awarded_only) = @_;
$links = 'no' if (! defined($links));
my $Str = ''; # final result string
my ($score,$max) = (0,0);
@@ -1457,16 +2055,20 @@ sub StudentPerformanceOnSequence {
my $symbol;
my @ScoreData = ();
my $partscore;
- foreach my $resource (@{$seq->{'contents'}}) {
- next if ($resource->{'type'} ne 'assessment');
- my $resource_data = $studentdata->{$resource->{'symb'}};
- foreach my $part (@{$resource->{'parts'}}) {
+ my $hasdata = 0; # flag, 0 if there were no submissions on the sequence
+ foreach my $resource (&get_resources($navmap,$seq)) {
+ my $symb = $resource->symb;
+ my $resource_data = $studentdata->{$symb};
+ foreach my $part (@{$resource->parts()}) {
$partscore = undef;
- my $weight = &Apache::lonnet::EXT('resource.'.$part.'.weight',
- $resource->{'symb'},
- $student->{'domain'},
- $student->{'username'},
- $student->{'section'});
+ my $weight;
+ if (!$awarded_only){
+ $weight = &Apache::lonnet::EXT('resource.'.$part.'.weight',
+ $symb,
+ $student->{'domain'},
+ $student->{'username'},
+ $student->{'section'});
+ }
if (!defined($weight) || ($weight eq '')) {
$weight=1;
}
@@ -1475,45 +2077,66 @@ sub StudentPerformanceOnSequence {
$performance_length++; # one character per part
$symbol = ' '; # default to space
#
- my $awarded = 0;
+ my $awarded;
if (exists($resource_data->{'resource.'.$part.'.awarded'})) {
$awarded = $resource_data->{'resource.'.$part.'.awarded'};
+ $awarded = 0 if (! $awarded);
+ $hasdata = 1;
}
#
- $partscore = $weight*$awarded;
+ $partscore = &Apache::grades::compute_points($weight,$awarded);
+ if (! defined($awarded)) {
+ $partscore = undef;
+ }
$score += $partscore;
- $symbol = $weight;
+ $symbol = $partscore;
+ if (abs($symbol - sprintf("%.0f",$symbol)) < 0.001) {
+ $symbol = sprintf("%.0f",$symbol);
+ }
if (length($symbol) > 1) {
- $symbol = '*';
+ $symbol = show_star($symbol);
}
- if (exists($resource_data->{'resource.'.$part.'.solved'})) {
+ if (exists($resource_data->{'resource.'.$part.'.solved'}) &&
+ $resource_data->{'resource.'.$part.'.solved'} ne '') {
my $status = $resource_data->{'resource.'.$part.'.solved'};
if ($status eq 'excused') {
$symbol = 'x';
$max -= $weight; # Do not count 'excused' problems.
+ } elsif ($status eq 'ungraded_attempted') {
+ $symbol = 'u';
}
- } else {
+ $hasdata = 1;
+ } elsif ($resource_data->{'resource.'.$part.'.award'} eq 'DRAFT') {
+ $symbol = 'd';
+ $hasdata = 1;
+ } elsif (!exists($resource_data->{'resource.'.$part.'.awarded'})){
# Unsolved. Did they try?
if (exists($resource_data->{'resource.'.$part.'.tries'})){
$symbol = '.';
+ $hasdata = 1;
} else {
$symbol = ' ';
}
}
#
- if ( ($links eq 'yes' && $symbol ne ' ') || ($links eq 'all')) {
- $symbol = ''.$symbol.'';
- }
if (! defined($partscore)) {
$partscore = $symbol;
}
push (@ScoreData,$partscore);
+ #
+ if ( ($links eq 'yes' && $symbol ne ' ') || ($links eq 'all')) {
+ my $link = '/adm/grades' .
+ '?symb='.&escape($resource->shown_symb).
+ '&student='.$student->{'username'}.
+ '&userdom='.$student->{'domain'}.
+ '&command=submission';
+ $symbol = &link($symbol, $link);
+ }
+ $Str .= $symbol;
}
- $Str .= $symbol;
+ }
+ if (! $hasdata && $score == 0) {
+ $score = ' ';
}
return ($Str,$performance_length,$score,$max,\@ScoreData);
}
@@ -1535,13 +2158,13 @@ problems.
#######################################################
sub CreateLegend {
my $Str = "
".
- " 1 correct by student in 1 try\n".
- " 7 correct by student in 7 tries\n".
+ " digit score or number of tries to get correct ".
" * correct by student in more than 9 tries\n".
" + correct by hand grading or override\n".
" - incorrect by override\n".
" . incorrect attempted\n".
- " # ungraded attempted\n".
+ " u ungraded attempted\n".
+ " d draft answer saved but not submitted\n".
" not attempted (blank field)\n".
" x excused".
"
";