');
hDoc.write("Text Color<\\/b><\\/td> Font Size<\\/b><\\/td> Font Style<\\/td><\\/tr>");
}
@@ -1680,7 +1704,7 @@ sub gradeBox {
my $radio.=''."\n"; # display radio buttons in a nice table 10 across
while ($thisweight<=$wgt) {
- $radio.= ' '.$thisweight." \n";
@@ -1696,7 +1720,7 @@ sub gradeBox {
$wgt.')" />'."\n";
$line.='/'.$wgt.' '.$wgtmsg.
($$record{'resource.'.$partid.'.solved'} eq 'correct_by_student' ? ' '.$checkIcon : '').
- ' '."\n";
+ ' '.&mt('Grade Status').': '."\n";
$line.=''."\n";
if ($$record{'resource.'.$partid.'.solved'} eq 'excused') {
@@ -1709,9 +1733,9 @@ sub gradeBox {
$line.=''.&mt('reset status').' '."\n";
+ #&mt('Part: [_1] Points: [_2] or [_3] ',$display_part,$radio,$line);
$result .=
- &mt('Part: [_1] Points: [_2] or [_3] ',$display_part,$radio,$line);
-
+ ''.&mt('Part:').' '.$display_part.' '.&mt('Points:').' '.$radio.' '.&mt('or').' '.$line.' '.
$result.='
'."\n";
$result.=' '."\n".
@@ -2090,10 +2114,12 @@ KEYWORDS
}
my $responsetype = $responseType->{$partid}->{$respid};
if (!exists($record{"resource.$partid.$respid.submission"})) {
- $lastsubonly.="\n".' Part: '.
- $display_part.' ( ID '.$respid.
- ' ) '.
- ''.&mt('Nothing submitted - no attempts').'
';
+ $lastsubonly.="\n".''.
+ ''.&mt('Part: [_1]',$display_part).' '.
+ ' '.
+ '('.&mt('Part ID: [_1]',$respid).')'.
+ ' '.
+ ''.&mt('Nothing submitted - no attempts.').'
';
next;
}
foreach my $submission (@$string) {
@@ -2112,10 +2138,9 @@ KEYWORDS
{'one_time' => 1});
$similar="".
- &mt('Essay is [_1]% similar to an essay by [_2] ([_3]:[_4]) in course [_5] (course id [_6]:[_7])',
+ &mt('Essay is [_1]% similar to an essay by [_2] in course [_3] (course id [_4]:[_5])',
$osim,
- &Apache::loncommon::plainname($oname,$odom),
- $oname,$odom,
+ &Apache::loncommon::plainname($oname,$odom).' ('.$oname.':'.$odom.')',
$old_course_desc{'description'},
$old_course_desc{'num'},
$old_course_desc{'domain'}).
@@ -2129,23 +2154,25 @@ KEYWORDS
($env{'form.lastSub'} eq 'hdgrade' &&
$$handgrade{$$part[0].'_'.$$part[1]} eq 'yes')) {
my $display_part=&get_display_part($partid,$symb);
- $lastsubonly.='Part: '.
- $display_part.'
( ID '.$respid.
- ' ) ';
+ $lastsubonly.='
'.
+ '
'.&mt('Part: [_1]',$display_part).' '.
+ '
'.
+ '('.&mt('Part ID: [_1]',$respid).')'.
+ ' ';
my $files=&get_submitted_files($udom,$uname,$partid,$respid,\%record);
if (@$files) {
- $lastsubonly.='
'.&mt('Like all files provided by users, this file may contain virusses').' ';
+ $lastsubonly.='
'.&mt('Like all files provided by users, this file may contain viruses').' ';
my $file_counter = 0;
foreach my $file (@$files) {
$file_counter++;
&Apache::lonnet::allowuploaded('/adm/grades',$file);
- $lastsubonly.='
'.$file.'';
+ $lastsubonly.='
'.$file.'';
}
$lastsubonly.='
';
}
$lastsubonly.='
'.&mt('Submitted Answer:').' '.
&cleanRecord($subval,$responsetype,$symb,$partid,
- $respid,\%record,$order);
+ $respid,\%record,$order,undef,$uname,$udom);
if ($similar) {$lastsubonly.="
$similar\n";}
$lastsubonly.='
';
}
@@ -2225,8 +2252,8 @@ KEYWORDS
$seen{$partid}++;
next if ($$handgrade{$part_resp} ne 'yes'
&& $env{'form.lastSub'} eq 'hdgrade');
- push @partlist,$partid;
- push @gradePartRespid,$partid.'.'.$respid;
+ push(@partlist,$partid);
+ push(@gradePartRespid,$partid.'.'.$respid);
$request->print(&gradeBox($request,$symb,$uname,$udom,$counter,$partid,\%record));
}
$request->print('
');
@@ -2274,7 +2301,7 @@ KEYWORDS
'7 10 '."\n";
my $nsel = ($env{'form.NTSTU'} ne '' ? $env{'form.NTSTU'} : '1');
$ntstu =~ s/$nsel $nsel;
- $endform.=&mt('[_1]student(s)',$ntstu);
+ $endform.=&mt('[quant,_1,student]',$ntstu);
$endform.=' '."\n".
' Nothing submitted - no attempts. ';
+ ''.&mt('Nothing submitted - no attempts.').' ';
}
return (\@string,\$timestamp);
}
@@ -2440,7 +2467,7 @@ sub processHandGrade {
undef,$feedurl,undef,
undef,undef,$showsymb,
$restitle);
- $request->print(' '.&mt('Sending message to [_1]:[_2]',$uname,$udom).': '.
+ $request->print(' '.&mt('Sending message to [_1]',$uname.':'.$udom).': '.
$msgstatus);
}
if ($env{'form.collaborator'.$ctr}) {
@@ -2553,7 +2580,7 @@ sub processHandGrade {
my (@parsedlist,@nextlist);
my ($nextflg) = 0;
- foreach (sort
+ foreach my $item (sort
{
if (lc($$fullname{$a}) ne lc($$fullname{$b})) {
return (lc($$fullname{$a}) cmp lc($$fullname{$b}));
@@ -2561,12 +2588,12 @@ sub processHandGrade {
return $a cmp $b;
} (keys(%$fullname))) {
if ($nextflg == 1 && $button =~ /Next$/) {
- push @parsedlist,$_;
+ push(@parsedlist,$item);
}
- $nextflg = 1 if ($_ eq $laststu);
+ $nextflg = 1 if ($item eq $laststu);
if ($button eq 'Previous') {
- last if ($_ eq $firststu);
- push @parsedlist,$_;
+ last if ($item eq $firststu);
+ push(@parsedlist,$item);
}
}
$ctr = 0;
@@ -2589,11 +2616,11 @@ sub processHandGrade {
my $submitted = 0;
my $ungraded = 0;
my $incorrect = 0;
- foreach (keys(%status)) {
- $submitted = 1 if ($status{$_} ne 'nothing');
- $ungraded = 1 if ($status{$_} =~ /^ungraded/);
- $incorrect = 1 if ($status{$_} =~ /^incorrect/);
- my ($foo,$partid,$foo1) = split(/\./,$_);
+ foreach my $item (keys(%status)) {
+ $submitted = 1 if ($status{$item} ne 'nothing');
+ $ungraded = 1 if ($status{$item} =~ /^ungraded/);
+ $incorrect = 1 if ($status{$item} =~ /^incorrect/);
+ my ($foo,$partid,$foo1) = split(/\./,$item);
if ($status{'resource.'.$partid.'.submitted_by'} ne '') {
$submitted = 0;
}
@@ -2604,7 +2631,7 @@ sub processHandGrade {
next if (!$ungraded && ($submitonly eq 'graded'));
next if (!$incorrect && $submitonly eq 'incorrect');
}
- push @nextlist,$student if ($ctr < $ntstu);
+ push(@nextlist,$student) if ($ctr < $ntstu);
last if ($ctr == $ntstu);
$ctr++;
}
@@ -2612,7 +2639,7 @@ sub processHandGrade {
$ctr = 0;
my $total = scalar(@nextlist)-1;
- foreach (sort @nextlist) {
+ foreach (sort(@nextlist)) {
my ($uname,$udom,$submitter) = split(/:/);
$env{'form.student'} = $uname;
$env{'form.userdom'} = $udom;
@@ -2658,7 +2685,7 @@ sub saveHandGrade {
}
} elsif ($dropMenu eq 'reset status'
&& exists($record{'resource.'.$new_part.'.solved'})) { #don't bother if no old records -> no attempts
- foreach my $key (keys (%record)) {
+ foreach my $key (keys(%record)) {
if ($key=~/^resource\.\Q$new_part\E\./) { $newrecord{$key} = ''; }
}
$newrecord{'resource.'.$new_part.'.regrader'}=
@@ -2693,7 +2720,7 @@ sub saveHandGrade {
&handback_files($request,$symb,$stuname,$domain,$newflg,$new_part,\%newrecord);
next;
} else {
- push @parts_graded, $new_part;
+ push(@parts_graded,$new_part);
}
if ($record{'resource.'.$new_part.'.awarded'} ne $partial) {
$newrecord{'resource.'.$new_part.'.awarded'} = $partial;
@@ -2720,7 +2747,7 @@ sub saveHandGrade {
$record{'resource.'.$new_part.'.solved'} eq 'incorrect_by_override' ||
$dropMenu eq 'reset status')
{
- push (@version_parts,$new_part);
+ push(@version_parts,$new_part);
}
}
my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
@@ -2795,8 +2822,10 @@ sub handback_files {
$newflg.'_'.$part_resp.'_returndoc'.$file_counter,
$save_file_name);
if ($result !~ m|^/uploaded/|) {
- $request->print('An error occurred ('.$result.
- ') while trying to upload '.$newflg.'_'.$part_resp.'_returndoc'.$file_counter.' ');
+ $request->print(''.
+ &mt('An error occurred ([_1]) while trying to upload [_2].',
+ $result,$newflg.'_'.$part_resp.'_returndoc'.$file_counter).
+ ' ');
} else {
# mark the file as read only
my @files = ($save_file_name);
@@ -2893,7 +2922,7 @@ sub decrement_aggs {
if ($aggtries == $totaltries) {
$decrement{'users'} = 1;
}
- foreach my $type (keys (%decrement)) {
+ foreach my $type (keys(%decrement)) {
$$aggregate{$symb."\0".$part."\0".$type} = -$decrement{$type};
}
return;
@@ -3015,6 +3044,7 @@ sub file_name_version_ext {
sub viewgrades_js {
my ($request) = shift;
+ my $alertmsg = &mt('A number equal or greater than 0 is expected. Entered value = ');
$request->print(<
function writePoint(partid,weight,point) {
@@ -3023,7 +3053,7 @@ sub viewgrades_js {
if (point == "textval") {
point = document.classgrade["TEXTVAL_"+partid].value;
if (isNaN(point) || parseFloat(point) < 0) {
- alert("A number equal or greater than 0 is expected. Entered value = "+parseFloat(point));
+ alert("$alertmsg"+parseFloat(point));
var resetbox = false;
for (var i=0; i '."\n".
' '."\n";
- my $sectionClass;
- my $section_display = join (", ",&Apache::loncommon::get_env_multiple('form.section'));
+ my ($common_header,$specific_header);
if ($env{'form.section'} eq 'all') {
- $sectionClass='Class';
+ $common_header = &mt('Assign Common Grade to Class');
+ $specific_header = &mt('Assign Grade to Specific Students in Class');
} elsif ($env{'form.section'} eq 'none') {
- $sectionClass='Students in no Section';
+ $common_header = &mt('Assign Common Grade to Students in no Section');
+ $specific_header = &mt('Assign Grade to Specific Students in no Section');
} else {
- $sectionClass='Students in Section(s) [_1]';
+ my $section_display = join (", ",&Apache::loncommon::get_env_multiple('form.section'));
+ $common_header = &mt('Assign Common Grade to Students in Section(s) [_1]',$section_display);
+ $specific_header = &mt('Assign Grade to Specific Students in Section(s) [_1]',$section_display);
}
- $result.=
- ''.
- &mt("Assign Common Grade To $sectionClass",$section_display).' ';
- $result.= &Apache::loncommon::start_data_table();
+ $result.= ''.$common_header.' '.&Apache::loncommon::start_data_table();
#radio buttons/text box for assigning points for a section or class.
#handles different parts of a problem
my ($partlist,$handgrade,$responseType) = &response_type($symb);
@@ -3253,8 +3283,8 @@ sub viewgrades {
my $line = ' /'.
- $weight{$partid}.' (problem weight) '."\n";
- $line.= ''."\n";
+ $line.= ''.&mt('Grade Status').': '.
' '.
@@ -3269,7 +3299,7 @@ sub viewgrades {
$result.=
&Apache::loncommon::start_data_table_row()."\n".
- &mt('Part: [_1] Points: [_2] or [_3] ',$display_part,$radio,$line).
+ ''.&mt('Part:').' '.$display_part.' '.&mt('Points:').' '.$radio.' '.&mt('or').' '.$line.' '.
&Apache::loncommon::end_data_table_row()."\n";
$ctsparts++;
}
@@ -3280,21 +3310,21 @@ sub viewgrades {
#table listing all the students in a section/class
#header of table
- $result.= ''.&mt('Assign Grade to Specific Students in '.$sectionClass,
- $section_display).' ';
- $result.= &Apache::loncommon::start_data_table().
- &Apache::loncommon::start_data_table_header_row().
- ''.&mt('No.').' '.
- ''.&nameUserString('header')." \n";
+ $result.= ''.$specific_header.' '.
+ &Apache::loncommon::start_data_table().
+ &Apache::loncommon::start_data_table_header_row().
+ ''.&mt('No.').' '.
+ ''.&nameUserString('header')." \n";
my (@parts) = sort(&getpartlist($symb));
my (undef,undef,$url)=&Apache::lonnet::decode_symb($symb);
my @partids = ();
foreach my $part (@parts) {
my $display=&Apache::lonnet::metadata($url,$part.'.display');
- $display =~ s|^Number of Attempts|Tries |; # makes the column narrower
+ my $narrowtext = &mt('Tries');
+ $display =~ s|^Number of Attempts|$narrowtext |; # makes the column narrower
if (!$display) { $display = &Apache::lonnet::metadata($url,$part.'.name'); }
my ($partid) = &split_part_type($part);
- push(@partids, $partid);
+ push(@partids,$partid);
my $display_part=&get_display_part($partid,$symb);
if ($display =~ /^Partial Credit Factor/) {
$result.=''.
@@ -3448,7 +3478,7 @@ sub editgrades {
my $header;
while ($ctr < $env{'form.totalparts'}) {
my $partid = $env{'form.partid_'.$ctr};
- push @partid,$partid;
+ push(@partid,$partid);
$weight{$partid} = $env{'form.weight_'.$partid};
$ctr++;
}
@@ -3462,10 +3492,11 @@ sub editgrades {
if ($part !~ m/^\Q$partid\E/) { next;}
if ($type eq 'awarded' || $type eq 'solved') { next; }
my $display=&Apache::lonnet::metadata($url,$stores.'.display');
- $display =~ s/\[Part: (\w)+\]//;
- $display =~ s/Number of Attempts/Tries/;
- $header .= ' '.&mt('Old '.$display).' '.
- ''.&mt('New '.$display).' ';
+ $display =~ s/\[Part: \Q$part\E\]//;
+ my $narrowtext = &mt('Tries');
+ $display =~ s/Number of Attempts/$narrowtext/;
+ $header .= ''.&mt('Old').' '.$display.' '.
+ ''.&mt('New').' '.$display.' ';
$columns{$partid}+=2;
}
}
@@ -3654,7 +3685,7 @@ sub split_part_type {
#
#--- Javascript to handle csv upload
sub csvupload_javascript_reverse_associate {
- my $error1=&mt('You need to specify the username or ID');
+ my $error1=&mt('You need to specify the username or the student/employee ID');
my $error2=&mt('You need to specify at least one grading field');
return(<
function checkUpload(formname) {
if (formname.upfile.value == "") {
- alert("Please use the browse button to select a file from your local directory.");
+ alert("$alertmsg");
return false;
}
formname.submit();
@@ -3831,8 +3863,8 @@ sub upcsvScores_form {
$result.=$table;
$result.=''."\n";
$result.=''."\n";
- $result.=' '.&mt('Specify a file containing the class scores for current resource').
- '. '."\n";
+ $result.=' '.&mt('Specify a file containing the class scores for current resource.').
+ ' '."\n";
$result.=''."\n";
my $upload=&mt("Upload Scores");
my $upfile_select=&Apache::loncommon::upfile_select_html();
@@ -4062,14 +4094,14 @@ sub csvuploadassign {
$countdone++;
}
}
- $request->print(''.&mt("Saved [_1] students",$countdone)." \n");
+ $request->print(' '.&Apache::lonhtmlcommon::confirm_success(&mt("Saved scores for [quant,_1,student]",$countdone),$countdone==0));
if (@skipped) {
- $request->print(''.&mt('Skipped Students').'
');
- foreach my $student (@skipped) { $request->print("$student \n"); }
+ $request->print(' '.&Apache::lonhtmlcommon::confirm_success(&mt('No scores stored for the following username(s):'),1).' ');
+ $request->print(join(', ',@skipped));
}
if (@notallowed) {
- $request->print(''.&mt('Students Not Allowed to Modify').'
');
- foreach my $student (@notallowed) { $request->print("$student \n"); }
+ $request->print(' '.&Apache::lonhtmlcommon::confirm_success(&mt('Modification of scores not allowed for the following username(s):'),1).' ');
+ $request->print(join(', ',@notallowed));
}
$request->print(" \n");
$request->print(&show_grading_menu_form($symb));
@@ -4085,12 +4117,13 @@ sub csvuploadassign {
sub pickStudentPage {
my ($request) = shift;
+ my $alertmsg = &mt('Please select the student you wish to grade.');
$request->print(<
function checkPickOne(formname) {
if (radioSelection(formname.student) == null) {
- alert("Please select the student you wish to grade.");
+ alert("$alertmsg");
return;
}
ptr = pullDownSelection(formname.selectpage);
@@ -4125,7 +4158,7 @@ LISTJAVASCRIPT
$ctr++;
}
$select.= '';
- $result.=&mt(' Problems from: [_1]',$select)." \n";
+ $result.=' '.&mt('Problems from').': '.$select." \n";
$ctr=0;
foreach (@$titles) {
@@ -4140,13 +4173,13 @@ LISTJAVASCRIPT
my $options =
' '.&mt('no').' '."\n".
' '.&mt('yes').' '." \n";
- $result.=' '.&mt('View Problems Text: [_1]',$options);
+ $result.=' '.&mt('View Problem Text').': '.$options;
$options =
' '.&mt('none').' '."\n".
' '.&mt('by dates and submissions').' '."\n".
' '.&mt('all details').' '."\n";
- $result.=' '.&mt('Submission Details: [_1]',$options);
+ $result.=' '.&mt('Submissions').': '.$options;
$result.=&build_section_inputs();
my $stu_status = join(':',&Apache::loncommon::get_env_multiple('form.Status'));
@@ -4155,12 +4188,10 @@ LISTJAVASCRIPT
' '."\n".
' '." \n";
- $result.=' '.&mt('Use CODE: [_1] ',
- ' ').
- ' '."\n";
+ $result.=' '.&mt('Use CODE').': '."\n";
$result.=' '."\n";
+ 'onClick="javascript:checkPickOne(this.form);" value="'.&mt('Next').' →" /> '."\n";
$request->print($result);
@@ -4199,7 +4230,7 @@ LISTJAVASCRIPT
}
$studentTable.=&Apache::loncommon::end_data_table()."\n";
$studentTable.=' '."\n";
+ 'onClick="javascript:checkPickOne(this.form);" value="'.&mt('Next').' →" />'."\n";
$studentTable.=&show_grading_menu_form($symb);
$request->print($studentTable);
@@ -4336,7 +4367,7 @@ sub displayPage {
# $request->print('match='.$1." \n");
# }
# $companswer =~ s|||g;
- $studentTable.=' '.$title.' '.&mt('Correct answer: [_1]',$companswer);
+ $studentTable.=' '.$title.' '.&mt('Correct answer').': '.$companswer;
}
my %record = &Apache::lonnet::restore($symbx,$env{'request.course.id'},$udom,$uname);
@@ -4406,10 +4437,11 @@ sub displaySubByDates {
my %orders;
$mark{'correct_by_student'} = $checkIcon;
if (!exists($$record{'1:timestamp'})) {
- return ' '.&mt('Nothing submitted - no attempts').' ';
+ return ' '.&mt('Nothing submitted - no attempts.').' ';
}
my $interaction;
+ my $no_increment = 1;
for ($version=1;$version<=$$record{'version'};$version++) {
my $timestamp =
&Apache::lonlocal::locallocaltime($$record{$version.':timestamp'});
@@ -4439,13 +4471,16 @@ sub displaySubByDates {
my ($responseId)= ($isTask ? ($matchKey=~ /^resource\.(.*?)\.\Q$partid\E\.award$/)
: ($matchKey=~ /^resource\.\Q$partid\E\.(.*?)\.submission$/));
- $displaySub[0].=''.&mt('Part:').' '.$display_part.' ';
- $displaySub[0].='('.&mt('ID').' '.
- $responseId.') ';
+ $displaySub[0].=''.&mt('Part: [_1]',$display_part).' '
+ .' '
+ .'('.&mt('Part ID: [_1]',$responseId).')'
+ .' '
+ .' ';
if ($$record{"$where.$partid.tries"} eq '') {
- $displaySub[0].=&mt('Trial not counted');
+ $displaySub[0].=&mt('Trial not counted');
} else {
- $displaySub[0].=&mt('Trial [_1]',
+ $displaySub[0].=&mt('Trial: [_1]',
$$record{"$where.$partid.tries"});
}
my $responseType=($isTask ? 'Task'
@@ -4453,9 +4488,11 @@ sub displaySubByDates {
if (!exists($orders{$partid})) { $orders{$partid}={}; }
if (!exists($orders{$partid}->{$responseId})) {
$orders{$partid}->{$responseId}=
- &get_order($partid,$responseId,$symb,$uname,$udom);
+ &get_order($partid,$responseId,$symb,$uname,$udom,
+ $no_increment);
}
- $displaySub[0].=' '.
+ $displaySub[0].=''; # /nobreak
+ $displaySub[0].=' '.
&cleanRecord($$record{$version.':'.$matchKey},$responseType,$symb,$partid,$responseId,$record,$orders{$partid}->{$responseId},"$version:",$uname,$udom).' ';
}
}
@@ -4506,12 +4543,12 @@ sub updateGradeByPage {
my ($uname,$udom) = split(/:/,$env{'form.student'});
my $usec=$classlist->{$env{'form.student'}}[5];
if (!&canmodify($usec)) {
- $request->print('Unable to modify requested student.('.$env{'form.student'}.' ');
+ $request->print(''.&mt('Unable to modify requested student ([_1])',$env{'form.student'}).' ');
$request->print(&show_grading_menu_form($env{'form.symb'}));
return;
}
my $result=' '.$env{'form.title'}.' ';
- $result.=' Student: '.&nameUserString(undef,$env{'form.fullname'},$uname,$udom).
+ $result.=' '.&mt('Student: ').&nameUserString(undef,$env{'form.fullname'},$uname,$udom).
' '."\n";
$request->print($result);
@@ -4520,7 +4557,7 @@ sub updateGradeByPage {
my ($mapUrl, $id, $resUrl) = &Apache::lonnet::decode_symb( $env{'form.page'});
my $map = $navmap->getResourceByUrl($resUrl); # add to navmaps
if (!$map) {
- $request->print('Unable to grade requested sequence. ('.$resUrl.') ');
+ $request->print(''.&mt('Unable to grade requested sequence ([_1]).',$resUrl).' ');
my ($symb)=&get_symb($request);
$request->print(&show_grading_menu_form($symb));
return;
@@ -4552,8 +4589,8 @@ sub updateGradeByPage {
&Apache::loncommon::start_data_table_row().
''.$prob.
(scalar(@{$parts}) == 1 ? ''
- : ' ('.&mt('[quant,_1, parts]',scalar(@{$parts}))
- ).') ';
+ : ' ('.&mt('[quant,_1, part]',scalar(@{$parts}))
+ .')').'';
$studentTable.=' '.$title.' ';
my %newrecord=();
@@ -4597,10 +4634,10 @@ sub updateGradeByPage {
}
my $display_part=&get_display_part($partid,$curRes->symb());
my $oldstatus = $env{'form.solved'.$question.'_'.$partid};
- $displayPts[0].=' Part: '.$display_part.' = '.
+ $displayPts[0].=' '.&mt('Part').': '.$display_part.' = '.
(($oldstatus eq 'excused') ? 'excused' : $oldpts).
' ';
- $displayPts[1].=' Part: '.$display_part.' = '.
+ $displayPts[1].=' '.&mt('Part').': '.$display_part.' = '.
(($score eq 'excused') ? 'excused' : $newpts).
' ';
$question++;
@@ -4649,9 +4686,9 @@ sub updateGradeByPage {
$studentTable.=&Apache::loncommon::end_data_table();
$studentTable.=&show_grading_menu_form($env{'form.symb'});
- my $grademsg=($changeflag == 0 ? 'No score was changed or updated.' :
- 'The scores were changed for '.
- $changeflag.' problem'.($changeflag == 1 ? '.' : 's.'));
+ my $grademsg=($changeflag == 0 ? &mt('No score was changed or updated.') :
+ &mt('The scores were changed for [quant,_1,problem].',
+ $changeflag));
$request->print($grademsg.$studentTable);
return '';
@@ -4688,10 +4725,10 @@ Next each scanline is checked for any er
bubbles' (it's an error because it may have been mis-scanned
because too light bubbling), 'double bubble' (each bubble line should
have no more that one letter picked), invalid or duplicated CODE,
-invalid student ID
+invalid student/employee ID
If the CODE option is used that determines the randomization of the
-homework problems, either way the student ID is looked up into a
+homework problems, either way the student/employee ID is looked up into a
username:domain.
During the validation phase the instructor can choose to skip scanlines.
@@ -4761,7 +4798,7 @@ sub getSequenceDropDown {
}
my %bubble_lines_per_response; # no. bubble lines for each response.
- # index is "symb.part_id"
+ # key is zero-based index - 0, 1, 2 ...
my %first_bubble_line; # First bubble line no. for each bubble.
@@ -4802,7 +4839,6 @@ sub restore_bubble_lines {
$env{"form.scantron.responsetype.$line"};
$line++;
}
-
}
# Given the parsed scanline, get the response for
@@ -4811,7 +4847,6 @@ sub restore_bubble_lines {
sub get_response_bubbles {
my ($parsed_line, $response) = @_;
-
my $bubble_line = $first_bubble_line{$response-1} +1;
my $bubble_lines= $bubble_lines_per_response{$response-1};
@@ -4908,7 +4943,7 @@ sub scantron_scantab {
domainconfig user, lines are from this file.
Otherwise, fall back to getting lines from the legacy file on the
- local server: /home/httpd/lonTabs/scantronformat.tab
+ local server: /home/httpd/lonTabs/default_scantronformat.tab
=cut
@@ -4936,9 +4971,16 @@ sub get_scantronformat_file {
}
}
if (!$gottab) {
- my $fh=Apache::File->new($Apache::lonnet::perlvar{'lonTabDir'}.'/scantronformat.tab');
- @lines = <$fh>;
- close($fh);
+ my @domains = &Apache::lonnet::current_machine_domains();
+ if (grep(/^\Q$cdom\E$/,@domains)) {
+ my $fh=Apache::File->new($Apache::lonnet::perlvar{'lonTabDir'}.'/scantronformat.tab');
+ @lines = <$fh>;
+ close($fh);
+ } else {
+ my $fh=Apache::File->new($Apache::lonnet::perlvar{'lonTabDir'}.'/default_scantronformat.tab');
+ @lines = <$fh>;
+ close($fh);
+ }
}
return @lines;
}
@@ -4975,11 +5017,11 @@ sub scantron_CODElist {
=cut
sub scantron_CODEunique {
- my $result='
+ my $result='
'.&mt('Yes').'
-
+
'.&mt('No').'
';
@@ -5035,10 +5077,10 @@ sub scantron_selectphase {
'.&mt('Sequence to grade:').' '.$sequence_selector.'
'.&Apache::loncommon::end_data_table_row().'
'.&Apache::loncommon::start_data_table_row().'
- '.&mt('Filename of scoring office file:').' '.$file_selector.'
+ '.&mt('Filename of bubblesheet data file:').' '.$file_selector.'
'.&Apache::loncommon::end_data_table_row().'
'.&Apache::loncommon::start_data_table_row().'
- '.&mt('Format of data file:').' '.$format_selector.'
+ '.&mt('Format of bubblesheet data file:').' '.$format_selector.'
'.&Apache::loncommon::end_data_table_row().'
'.&Apache::loncommon::start_data_table_row().'
'.&mt('Saved CODEs to validate against:').' '.$CODE_selector.'
@@ -5056,7 +5098,7 @@ sub scantron_selectphase {
'.&Apache::loncommon::end_data_table_row().'
'.&Apache::loncommon::start_data_table_row().'
-
+
'.&Apache::loncommon::end_data_table_row().'
'.&Apache::loncommon::end_data_table().'
@@ -5075,7 +5117,7 @@ sub scantron_selectphase {
'.&Apache::loncommon::start_data_table('LC_scantron_action').'
'.&Apache::loncommon::start_data_table_header_row().'
- '.&mt('Specify a Scantron data file to upload.').'
+ '.&mt('Specify a bubblesheet data file to upload.').'
'.&Apache::loncommon::end_data_table_header_row().'
'.&Apache::loncommon::start_data_table_row().'
@@ -5102,7 +5144,7 @@ sub scantron_selectphase {
'.&mt('File to upload: [_1]',' ').'
-
+
');
@@ -5138,8 +5180,41 @@ sub scantron_selectphase {
');
&Apache::lonpickcode::code_list($r,2);
+
+ $r->print(' ');
$r->print($grading_menu_button);
- return
+ return;
}
=pod
@@ -5174,8 +5249,8 @@ sub scantron_selectphase {
CODEstart - (only matter if a CODE exists) column in the line where
the CODE starts
CODElength - length of the CODE
- IDstart - column where the student ID number starts
- IDlength - length of the student ID info
+ IDstart - column where the student/employee ID starts
+ IDlength - length of the student/employee ID info
Qstart - column where the information from the bubbled
'questions' start
Qlength - number of columns comprising a single bubble line from
@@ -5235,7 +5310,7 @@ sub get_scantron_config {
=item username_to_idmap
- creates a hash keyed by student id with values of the corresponding
+ creates a hash keyed by student/employee ID with values of the corresponding
student username:domain.
Arguments:
@@ -5274,7 +5349,7 @@ sub username_to_idmap {
$whichline - line number of the passed in scanline
$field - type of change to process
(either
- 'ID' -> correct the student ID number
+ 'ID' -> correct the student/employee ID
'CODE' -> correct the CODE
'answer' -> fixup the submitted answers)
@@ -5448,7 +5523,7 @@ sub digits_to_letters {
CODE_ignore_dup - 1 if the CODE is a duplicated use when unique
CODEs were selected, but the usage has been
forced by the operator
- ID - student ID
+ ID - student/employee ID
PaperID - if used, the ID number printed on the sheet when the
paper was scanned
FirstName - first name from the sheet
@@ -5484,7 +5559,8 @@ sub scantron_parse_scanline {
my ($line,$whichline,$scantron_config,$scan_data,$just_header)=@_;
my %record;
- my $questions=substr($line,$$scantron_config{'Qstart'}-1); # Answers
+ my $lastpos = $env{'form.scantron_maxbubble'}*$$scantron_config{'Qlength'};
+ my $questions=substr($line,$$scantron_config{'Qstart'}-1,$lastpos); # Answers
my $data=substr($line,0,$$scantron_config{'Qstart'}-1); # earlier stuff
if (!($$scantron_config{'CODElocation'} eq 0 ||
$$scantron_config{'CODElocation'} eq 'none')) {
@@ -6174,27 +6250,33 @@ sub scantron_validate_file {
}
if (!$stop) {
my $warning=&scantron_warning_screen('Start Grading');
- $r->print(&mt('Validation process complete.').'
-'.$warning.'
-
-
-');
-
+ $r->print(&mt('Validation process complete.').' '.
+ $warning.
+ &mt('Perform verification for each student after storage of submissions?').
+ ' '.
+ ' '.&mt('Yes').' '.
+ (' 'x3).''.
+ ' '.&mt('No').
+ ' '.
+ &mt('Grading will take longer if you use verification.').' '.
+ &mt("Alternatively, the 'Review bubblesheet data' utility (see grading menu) can be used for all students after grading is complete.").' '.
+ ' '.
+ ' '."\n");
} else {
$r->print(' ');
$r->print(" ");
}
if ($stop) {
if ($validate_phases[$currentphase] eq 'sequence') {
- $r->print(' ');
+ $r->print(' ');
$r->print(' '.&mt('this error').' ');
$r->print(" ".&mt("Or click the 'Grading Menu' button to start over.")."
");
} else {
if ($validate_phases[$currentphase] eq 'doublebubble' || $validate_phases[$currentphase] eq 'missingbubbles') {
- $r->print(' ');
+ $r->print(' ');
} else {
- $r->print(' ');
+ $r->print(' ');
}
$r->print(' '.&mt('using corrected info').' ');
$r->print(" ");
@@ -6572,14 +6654,7 @@ sub scantron_validate_sequence {
return (0,$currentphase+1);
}
-=pod
-
-=item scantron_validate_ID
- Validates all scanlines in the selected file to not have any
- invalid or underspecified student IDs
-
-=cut
sub scantron_validate_ID {
my ($r,$currentphase) = @_;
@@ -6645,35 +6720,6 @@ sub scantron_validate_ID {
return (0,$currentphase+1);
}
-=pod
-
-=item scantron_get_correction
-
- Builds the interface screen to interact with the operator to fix a
- specific error condition in a specific scanline
-
- Arguments:
- $r - Apache request object
- $i - number of the current scanline
- $scan_record - hash ref as returned from &scantron_parse_scanline()
- $scan_config - hash ref as returned from &get_scantron_config()
- $line - full contents of the current scanline
- $error - error condition, valid values are
- 'incorrectCODE', 'duplicateCODE',
- 'doublebubble', 'missingbubble',
- 'duplicateID', 'incorrectID'
- $arg - extra information needed
- For errors:
- - duplicateID - paper number that this studentID was seen before on
- - duplicateCODE - array ref of the paper numbers this CODE was
- seen on before
- - incorrectCODE - current incorrect CODE
- - doublebubble - array ref of the bubble lines that have double
- bubble errors
- - missingbubble - array ref of the bubble lines that have missing
- bubble errors
-
-=cut
sub scantron_get_correction {
my ($r,$i,$scan_record,$scan_config,$line,$error,$arg)=@_;
@@ -6739,10 +6785,10 @@ sub scantron_get_correction {
if ($closest > 0) {
foreach my $testcode (@{$closest}) {
my $checked='';
- if (!$i) { $checked=' checked="checked" '; }
+ if (!$i) { $checked=' checked="checked"'; }
$r->print("
-
+
".&mt("Use the similar CODE [_1] instead.",
"".$testcode." ")."
@@ -6753,10 +6799,10 @@ sub scantron_get_correction {
}
}
if ($$scan_record{'scantron.CODE'}=~/\S/ ) {
- my $checked; if (!$i) { $checked=' checked="checked" '; }
+ my $checked; if (!$i) { $checked=' checked="checked"'; }
$r->print("
-
+
".&mt("Use the CODE [_1] that is was on the paper, ignoring the error.",
"".$$scan_record{'scantron.CODE'}." ")."
");
@@ -6787,7 +6833,7 @@ ENDSCRIPT
".&mt("[_1]Select[_2] a CODE from the list of all CODEs and use it.",
""," ")."
- ".&mt("Selected CODE is [_1]"," "));
+ ".&mt("Selected CODE is [_1]",' '));
$r->print("\n ");
}
$r->print("
@@ -6811,7 +6857,7 @@ ENDSCRIPT
foreach my $question (@{$arg}) {
my @linenums = &prompt_for_corrections($r,$question,$scan_config,
$scan_record, $error);
- push (@lines_to_correct,@linenums);
+ push(@lines_to_correct,@linenums);
}
$r->print(&verify_bubbles_checked(@lines_to_correct));
} elsif ($error eq 'missingbubble') {
@@ -6831,7 +6877,7 @@ ENDSCRIPT
foreach my $question (@{$arg}) {
my @linenums = &prompt_for_corrections($r,$question,$scan_config,
$scan_record, $error);
- push (@lines_to_correct,@linenums);
+ push(@lines_to_correct,@linenums);
}
$r->print(&verify_bubbles_checked(@lines_to_correct));
} else {
@@ -6980,7 +7026,7 @@ sub prompt_for_corrections {
($responsetype_per_response{$question-1} eq 'imageresponse') ||
($responsetype_per_response{$question-1} eq 'reactionresponse') ||
($responsetype_per_response{$question-1} eq 'organicresponse')) {
- $r->print(&mt("Although this particular question type requires handgrading, the instructions for this question in the exam directed students to leave [quant,_1,line] blank on their scantron sheets.",$lines).' '.&mt('A non-zero score can be assigned to the student during scantron grading by selecting a bubble in at least one line.').' '.&mt('The score for this question will be a sum of the numeric values for the selected bubbles from each line, where A=1 point, B=2 points etc.').' '.&mt("To assign a score of zero for this question, mark all lines as 'No bubble'.").' ');
+ $r->print(&mt("Although this particular question type requires handgrading, the instructions for this question in the exam directed students to leave [quant,_1,line] blank on their bubblesheets.",$lines).' '.&mt('A non-zero score can be assigned to the student during bubblesheet grading by selecting a bubble in at least one line.').' '.&mt('The score for this question will be a sum of the numeric values for the selected bubbles from each line, where A=1 point, B=2 points etc.').' '.&mt("To assign a score of zero for this question, mark all lines as 'No bubble'.").' ');
} else {
$r->print(&mt("Select at most one bubble in a single line and select 'No Bubble' in all the other lines. ")." ");
}
@@ -6989,7 +7035,7 @@ sub prompt_for_corrections {
my $selected = $$scan_record{"scantron.$current_line.answer"};
&scantron_bubble_selector($r,$scan_config,$current_line,
$questionnum,$error,split('', $selected));
- push (@linenums,$current_line);
+ push(@linenums,$current_line);
$current_line++;
}
if ($lines > 1) {
@@ -7205,7 +7251,7 @@ sub scantron_validate_CODE {
$line,'duplicateCODE',$usedCODEs{$CODE});
return(1,$currentphase);
}
- push (@{$usedCODEs{$CODE}},$$scan_record{'scantron.PaperID'});
+ push(@{$usedCODEs{$CODE}},$$scan_record{'scantron.PaperID'});
}
return (0,$currentphase+1);
}
@@ -7244,25 +7290,6 @@ sub scantron_validate_doublebubble {
return (0,$currentphase+1);
}
-=pod
-
-=item scantron_get_maxbubble
-
- Returns the maximum number of bubble lines that are expected to
- occur. Does this by walking the selected sequence rendering the
- resource and then checking &Apache::lonxml::get_problem_counter()
- for what the current value of the problem counter is.
-
- Caches the results to $env{'form.scantron_maxbubble'},
- $env{'form.scantron.bubble_lines.n'},
- $env{'form.scantron.first_bubble_line.n'} and
- $env{"form.scantron.sub_bubblelines.n"}
- which are the total number of bubble, lines, the number of bubble
- lines for response n and number of the first bubble line for response n,
- and a comma separated list of numbers of bubble lines for sub-questions
- (for optionresponse, matchresponse, and rankresponse items), for response n.
-
-=cut
sub scantron_get_maxbubble {
if (defined($env{'form.scantron_maxbubble'}) &&
@@ -7280,116 +7307,74 @@ sub scantron_get_maxbubble {
&Apache::lonxml::clear_problem_counter();
- my $uname = $env{'form.student'};
- my $udom = $env{'form.userdom'};
+ my $uname = $env{'user.name'};
+ my $udom = $env{'user.domain'};
my $cid = $env{'request.course.id'};
my $total_lines = 0;
%bubble_lines_per_response = ();
%first_bubble_line = ();
%subdivided_bubble_lines = ();
%responsetype_per_response = ();
-
+
my $response_number = 0;
my $bubble_line = 0;
foreach my $resource (@resources) {
- my $symb = $resource->symb();
- # Need to retrieve part IDs and response IDs because essayresponse,
- # reactionresponse and organicresponse items are not included in
- # $analysis{'parts'} from lonnet::ssi.
- my %possible_part_ids;
- if (ref($resource->parts()) eq 'ARRAY') {
- foreach my $part (@{$resource->parts()}) {
- if (!&Apache::loncommon::check_if_partid_hidden($part,$symb,$udom,$uname)) {
- my @resp_ids = $resource->responseIds($part);
- foreach my $id (@resp_ids) {
- $possible_part_ids{$part.'.'.$id} = 1;
+ my ($analysis,$parts) = &scantron_partids_tograde($resource,$cid,$uname,$udom);
+ if ((ref($analysis) eq 'HASH') && (ref($parts) eq 'ARRAY')) {
+ foreach my $part_id (@{$parts}) {
+ my $lines;
+
+ # TODO - make this a persistent hash not an array.
+
+ # optionresponse, matchresponse and rankresponse type items
+ # render as separate sub-questions in exam mode.
+ if (($analysis->{$part_id.'.type'} eq 'optionresponse') ||
+ ($analysis->{$part_id.'.type'} eq 'matchresponse') ||
+ ($analysis->{$part_id.'.type'} eq 'rankresponse')) {
+ my ($numbub,$numshown);
+ if ($analysis->{$part_id.'.type'} eq 'optionresponse') {
+ if (ref($analysis->{$part_id.'.options'}) eq 'ARRAY') {
+ $numbub = scalar(@{$analysis->{$part_id.'.options'}});
+ }
+ } elsif ($analysis->{$part_id.'.type'} eq 'matchresponse') {
+ if (ref($analysis->{$part_id.'.items'}) eq 'ARRAY') {
+ $numbub = scalar(@{$analysis->{$part_id.'.items'}});
+ }
+ } elsif ($analysis->{$part_id.'.type'} eq 'rankresponse') {
+ if (ref($analysis->{$part_id.'.foils'}) eq 'ARRAY') {
+ $numbub = scalar(@{$analysis->{$part_id.'.foils'}});
+ }
}
- }
- }
- }
- my $result=&ssi_with_retries($resource->src(), $ssi_retries,
- ('symb' => $symb,
- 'grade_target' => 'analyze',
- 'grade_courseid' => $cid,
- 'grade_domain' => $udom,
- 'grade_username' => $uname));
- my (undef, $an) =
- split(/_HASH_REF__/,$result, 2);
-
- my @parts;
-
- my %analysis = &Apache::lonnet::str2hash($an);
-
- if (ref($analysis{'parts'}) eq 'ARRAY') {
- foreach my $part (@{$analysis{'parts'}}) {
- my ($id,$respid) = split(/\./,$part);
- if (!&Apache::loncommon::check_if_partid_hidden($id,$symb,$udom,$uname)) {
- push(@parts,$part);
- }
- }
- }
- # Add part_ids for any essayresponse items.
- foreach my $part_id (keys(%possible_part_ids)) {
- if (($analysis{$part_id.'.type'} eq 'essayresponse') ||
- ($analysis{$part_id.'.type'} eq 'reactionresponse') ||
- ($analysis{$part_id.'.type'} eq 'organicresponse')) {
- if (!grep(/^\Q$part_id\E$/,@parts)) {
- push (@parts,$part_id);
- }
- }
- }
-
- foreach my $part_id (@parts) {
- my $lines = $analysis{"$part_id.bubble_lines"};
-
- # TODO - make this a persistent hash not an array.
-
- # optionresponse, matchresponse and rankresponse type items
- # render as separate sub-questions in exam mode.
- if (($analysis{$part_id.'.type'} eq 'optionresponse') ||
- ($analysis{$part_id.'.type'} eq 'matchresponse') ||
- ($analysis{$part_id.'.type'} eq 'rankresponse')) {
- my ($numbub,$numshown);
- if ($analysis{$part_id.'.type'} eq 'optionresponse') {
- if (ref($analysis{$part_id.'.options'}) eq 'ARRAY') {
- $numbub = scalar(@{$analysis{$part_id.'.options'}});
+ if (ref($analysis->{$part_id.'.shown'}) eq 'ARRAY') {
+ $numshown = scalar(@{$analysis->{$part_id.'.shown'}});
}
- } elsif ($analysis{$part_id.'.type'} eq 'matchresponse') {
- if (ref($analysis{$part_id.'.items'}) eq 'ARRAY') {
- $numbub = scalar(@{$analysis{$part_id.'.items'}});
+ my $bubbles_per_line = 10;
+ my $inner_bubble_lines = int($numbub/$bubbles_per_line);
+ if (($numbub % $bubbles_per_line) != 0) {
+ $inner_bubble_lines++;
}
- } elsif ($analysis{$part_id.'.type'} eq 'rankresponse') {
- if (ref($analysis{$part_id.'.foils'}) eq 'ARRAY') {
- $numbub = scalar(@{$analysis{$part_id.'.foils'}});
+ for (my $i=0; $i<$numshown; $i++) {
+ $subdivided_bubble_lines{$response_number} .=
+ $inner_bubble_lines.',';
}
- }
- if (ref($analysis{$part_id.'.shown'}) eq 'ARRAY') {
- $numshown = scalar(@{$analysis{$part_id.'.shown'}});
- }
- my $bubbles_per_line = 10;
- my $inner_bubble_lines = int($numshown/$bubbles_per_line);
- if (($numshown % $bubbles_per_line) != 0) {
- $inner_bubble_lines++;
- }
- for (my $i=0; $i<$numshown; $i++) {
- $subdivided_bubble_lines{$response_number} .=
- $inner_bubble_lines.',';
- }
- $subdivided_bubble_lines{$response_number} =~ s/,$//;
- }
+ $subdivided_bubble_lines{$response_number} =~ s/,$//;
+ $lines = $numshown * $inner_bubble_lines;
+ } else {
+ $lines = $analysis->{"$part_id.bubble_lines"};
+ }
- $first_bubble_line{$response_number} = $bubble_line;
- $bubble_lines_per_response{$response_number} = $lines;
- $responsetype_per_response{$response_number} =
- $analysis{$part_id.'.type'};
- $response_number++;
-
- $bubble_line += $lines;
- $total_lines += $lines;
- }
+ $first_bubble_line{$response_number} = $bubble_line;
+ $bubble_lines_per_response{$response_number} = $lines;
+ $responsetype_per_response{$response_number} =
+ $analysis->{$part_id.'.type'};
+ $response_number++;
+ $bubble_line += $lines;
+ $total_lines += $lines;
+ }
+ }
}
- &Apache::lonnet::delenv('scantron\.');
+ &Apache::lonnet::delenv('scantron.');
&save_bubble_lines();
$env{'form.scantron_maxbubble'} =
@@ -7397,16 +7382,6 @@ sub scantron_get_maxbubble {
return $env{'form.scantron_maxbubble'};
}
-=pod
-
-=item scantron_validate_missingbubbles
-
- Validates all scanlines in the selected file to not have any
- answers that don't have bubbles that have not been verified
- to be bubble free.
-
-=cut
-
sub scantron_validate_missingbubbles {
my ($r,$currentphase) = @_;
#get student info
@@ -7460,29 +7435,6 @@ sub scantron_validate_missingbubbles {
return (0,$currentphase+1);
}
-=pod
-
-=item scantron_process_students
-
- Routine that does the actual grading of the bubble sheet information.
-
- The parsed scanline hash is added to %env
-
- Then foreach unskipped scanline it does an &Apache::lonnet::ssi()
- foreach resource , with the form data of
-
- 'submitted' =>'scantron'
- 'grade_target' =>'grade',
- 'grade_username'=> username of student
- 'grade_domain' => domain of student
- 'grade_courseid'=> of course
- 'grade_symb' => symb of resource to grade
-
- This triggers a grading pass. The problem grading code takes care
- of converting the bubbled letter information (now in %env) into a
- valid submission.
-
-=cut
sub scantron_process_students {
my ($r) = @_;
@@ -7501,7 +7453,24 @@ sub scantron_process_students {
my $navmap=Apache::lonnavmaps::navmap->new();
my $map=$navmap->getResourceByUrl($sequence);
my @resources=$navmap->retrieveResources($map,\&scantron_filter,1,0);
-# $r->print("geto ".scalar(@resources)." ");
+ my (%grader_partids_by_symb,%grader_randomlists_by_symb);
+ &graders_resources_pass(\@resources,\%grader_partids_by_symb,
+ \%grader_randomlists_by_symb);
+ foreach my $resource (@resources) {
+ my $ressymb = $resource->symb();
+ my ($analysis,$parts) =
+ &scantron_partids_tograde($resource,$env{'request.course.id'},
+ $env{'user.name'},$env{'user.domain'},1);
+ $grader_partids_by_symb{$ressymb} = $parts;
+ if (ref($analysis) eq 'HASH') {
+ if (ref($analysis->{'parts_withrandomlist'}) eq 'ARRAY') {
+ $grader_randomlists_by_symb{$ressymb} =
+ $analysis->{'parts_withrandomlist'};
+ }
+ }
+ }
+
+ my ($uname,$udom);
my $result= <
@@ -7510,20 +7479,21 @@ SCANTRONFORM
$r->print($result);
my @delayqueue;
- my %completedstudents;
+ my (%completedstudents,%scandata);
+ my $lock=&Apache::lonnet::set_lock(&mt('Grading bubblesheet exam'));
my $count=&get_todo_count($scanlines,$scan_data);
- my %prog_state=&Apache::lonhtmlcommon::Create_PrgWin($r,'Scantron Status',
- 'Scantron Progress',$count,
+ my %prog_state=&Apache::lonhtmlcommon::Create_PrgWin($r,'Bubblesheet Status',
+ 'Bubblesheet Progress',$count,
'inline',undef,'scantronupload');
&Apache::lonhtmlcommon::Update_PrgWin($r,\%prog_state,
'Processing first student');
+ $r->print(' ');
my $start=&Time::HiRes::time();
my $i=-1;
- my ($uname,$udom,$started);
+ my $started;
&scantron_get_maxbubble(); # Need the bubble lines array to parse.
-
# If an ssi failed in scantron_get_maxbubble, put an error message out to
# the user and return.
@@ -7532,9 +7502,13 @@ SCANTRONFORM
$r->print("");
&ssi_print_error($r);
$r->print(&show_grading_menu_form($symb));
+ &Apache::lonnet::remove_lock($lock);
return ''; # Dunno why the other returns return '' rather than just returning.
}
+ my %lettdig = &letter_to_digits();
+ my $numletts = scalar(keys(%lettdig));
+
while ($i<$scanlines->{'count'}) {
($uname,$udom)=('','');
$i++;
@@ -7560,6 +7534,19 @@ SCANTRONFORM
}
($uname,$udom)=split(/:/,$uname);
+ my %partids_by_symb;
+ foreach my $resource (@resources) {
+ my $ressymb = $resource->symb();
+ if ((exists($grader_randomlists_by_symb{$ressymb})) ||
+ (ref($grader_partids_by_symb{$ressymb}) ne 'ARRAY')) {
+ my ($analysis,$parts) =
+ &scantron_partids_tograde($resource,$env{'request.course.id'},$uname,$udom);
+ $partids_by_symb{$ressymb} = $parts;
+ } else {
+ $partids_by_symb{$ressymb} = $grader_partids_by_symb{$ressymb};
+ }
+ }
+
&Apache::lonxml::clear_problem_counter();
&Apache::lonnet::appenv($scan_record);
@@ -7567,40 +7554,99 @@ SCANTRONFORM
&scantron_putfile($scanlines,$scan_data);
}
- my $i=0;
- foreach my $resource (@resources) {
- $i++;
- my %form=('submitted' =>'scantron',
- 'grade_target' =>'grade',
- 'grade_username'=>$uname,
- 'grade_domain' =>$udom,
- 'grade_courseid'=>$env{'request.course.id'},
- 'grade_symb' =>$resource->symb());
- if (exists($scan_record->{'scantron.CODE'})
- &&
- &Apache::lonnet::validCODE($scan_record->{'scantron.CODE'})) {
- $form{'CODE'}=$scan_record->{'scantron.CODE'};
- } else {
- $form{'CODE'}='';
- }
- my $result=&ssi_with_retries($resource->src(), $ssi_retries, %form);
- if ($ssi_error) {
- $ssi_error = 0; # So end of handler error message does not trigger.
- $r->print("");
- &ssi_print_error($r);
- $r->print(&show_grading_menu_form($symb));
- return ''; # Why return ''? Beats me.
- }
+ my $scancode;
+ if ((exists($scan_record->{'scantron.CODE'})) &&
+ (&Apache::lonnet::validCODE($scan_record->{'scantron.CODE'}))) {
+ $scancode = $scan_record->{'scantron.CODE'};
+ } else {
+ $scancode = '';
+ }
+
+ if (&grade_student_bubbles($r,$uname,$udom,$scan_record,$scancode,
+ \@resources,\%partids_by_symb) eq 'ssi_error') {
+ $ssi_error = 0; # So end of handler error message does not trigger.
+ $r->print("");
+ &ssi_print_error($r);
+ $r->print(&show_grading_menu_form($symb));
+ &Apache::lonnet::remove_lock($lock);
+ return ''; # Why return ''? Beats me.
+ }
- if (&Apache::loncommon::connection_aborted($r)) { last; }
- }
$completedstudents{$uname}={'line'=>$line};
- if (&Apache::loncommon::connection_aborted($r)) { last; }
+ if ($env{'form.verifyrecord'}) {
+ my $lastpos = $env{'form.scantron_maxbubble'}*$scantron_config{'Qlength'};
+ my $studentdata = substr($line,$scantron_config{'Qstart'}-1,$lastpos);
+ chomp($studentdata);
+ $studentdata =~ s/\r$//;
+ my $studentrecord = '';
+ my $counter = -1;
+ foreach my $resource (@resources) {
+ my $ressymb = $resource->symb();
+ ($counter,my $recording) =
+ &verify_scantron_grading($resource,$udom,$uname,$env{'request.course.id'},
+ $counter,$studentdata,$partids_by_symb{$ressymb},
+ \%scantron_config,\%lettdig,$numletts);
+ $studentrecord .= $recording;
+ }
+ if ($studentrecord ne $studentdata) {
+ &Apache::lonxml::clear_problem_counter();
+ if (&grade_student_bubbles($r,$uname,$udom,$scan_record,$scancode,
+ \@resources,\%partids_by_symb) eq 'ssi_error') {
+ $ssi_error = 0; # So end of handler error message does not trigger.
+ $r->print("");
+ &ssi_print_error($r);
+ $r->print(&show_grading_menu_form($symb));
+ &Apache::lonnet::remove_lock($lock);
+ delete($completedstudents{$uname});
+ return '';
+ }
+ $counter = -1;
+ $studentrecord = '';
+ foreach my $resource (@resources) {
+ my $ressymb = $resource->symb();
+ ($counter,my $recording) =
+ &verify_scantron_grading($resource,$udom,$uname,$env{'request.course.id'},
+ $counter,$studentdata,$partids_by_symb{$ressymb},
+ \%scantron_config,\%lettdig,$numletts);
+ $studentrecord .= $recording;
+ }
+ if ($studentrecord ne $studentdata) {
+ $r->print('');
+ if ($scancode eq '') {
+ $r->print(&mt('Mismatch grading bubble sheet for user: [_1] with ID: [_2].',
+ $uname.':'.$udom,$scan_record->{'scantron.ID'}));
+ } else {
+ $r->print(&mt('Mismatch grading bubble sheet for user: [_1] with ID: [_2] and CODE: [_3].',
+ $uname.':'.$udom,$scan_record->{'scantron.ID'},$scancode));
+ }
+ $r->print(' '.&Apache::loncommon::start_data_table()."\n".
+ &Apache::loncommon::start_data_table_header_row()."\n".
+ '
'.&mt('Source').' '.&mt('Bubbled responses').' '.
+ &Apache::loncommon::end_data_table_header_row()."\n".
+ &Apache::loncommon::start_data_table_row().
+ ''.&mt('Bubble Sheet').' '.
+ ''.$studentdata.' '.
+ &Apache::loncommon::end_data_table_row().
+ &Apache::loncommon::start_data_table_row().
+ 'Stored submissions '.
+ ''.$studentrecord.' '."\n".
+ &Apache::loncommon::end_data_table_row().
+ &Apache::loncommon::end_data_table().'');
+ } else {
+ $r->print(''.
+ &mt('A second grading pass was needed for user: [_1] with ID: [_2], because a mismatch was seen on the first pass.',$uname.':'.$udom,$scan_record->{'scantron.ID'}).' '.
+ &mt("As a consequence, this user's submission history records two tries.").
+ ' ');
+ }
+ }
+ }
+ if (&Apache::loncommon::connection_aborted($r)) { last; }
} continue {
&Apache::lonxml::clear_problem_counter();
- &Apache::lonnet::delenv('scantron\.');
+ &Apache::lonnet::delenv('scantron.');
}
&Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state);
+ &Apache::lonnet::remove_lock($lock);
# my $lasttime = &Time::HiRes::time()-$start;
# $r->print("took $lasttime
");
@@ -7609,62 +7655,125 @@ SCANTRONFORM
return '';
}
-=pod
-
-=item scantron_upload_scantron_data
-
- Creates the screen for adding a new bubble sheet data file to a course.
+sub graders_resources_pass {
+ my ($resources,$grader_partids_by_symb,$grader_randomlists_by_symb) = @_;
+ if ((ref($resources) eq 'ARRAY') && (ref($grader_partids_by_symb)) &&
+ (ref($grader_randomlists_by_symb) eq 'HASH')) {
+ foreach my $resource (@{$resources}) {
+ my $ressymb = $resource->symb();
+ my ($analysis,$parts) =
+ &scantron_partids_tograde($resource,$env{'request.course.id'},
+ $env{'user.name'},$env{'user.domain'},1);
+ $grader_partids_by_symb->{$ressymb} = $parts;
+ if (ref($analysis) eq 'HASH') {
+ if (ref($analysis->{'parts_withrandomlist'}) eq 'ARRAY') {
+ $grader_randomlists_by_symb->{$ressymb} =
+ $analysis->{'parts_withrandomlist'};
+ }
+ }
+ }
+ }
+ return;
+}
-=cut
+sub grade_student_bubbles {
+ my ($r,$uname,$udom,$scan_record,$scancode,$resources,$parts) = @_;
+ if (ref($resources) eq 'ARRAY') {
+ my $count = 0;
+ foreach my $resource (@{$resources}) {
+ my $ressymb = $resource->symb();
+ my %form = ('submitted' => 'scantron',
+ 'grade_target' => 'grade',
+ 'grade_username' => $uname,
+ 'grade_domain' => $udom,
+ 'grade_courseid' => $env{'request.course.id'},
+ 'grade_symb' => $ressymb,
+ 'CODE' => $scancode
+ );
+ if (ref($parts) eq 'HASH') {
+ if (ref($parts->{$ressymb}) eq 'ARRAY') {
+ foreach my $part (@{$parts->{$ressymb}}) {
+ $form{'scantron_questnum_start.'.$part} =
+ 1+$env{'form.scantron.first_bubble_line.'.$count};
+ $count++;
+ }
+ }
+ }
+ my $result=&ssi_with_retries($resource->src(),$ssi_retries,%form);
+ return 'ssi_error' if ($ssi_error);
+ last if (&Apache::loncommon::connection_aborted($r));
+ }
+ }
+ return;
+}
sub scantron_upload_scantron_data {
my ($r)=@_;
- $r->print(&Apache::loncommon::coursebrowser_javascript($env{'request.role.domain'}));
+ my $dom = $env{'request.role.domain'};
+ my $domdesc = &Apache::lonnet::domain($dom,'description');
+ $r->print(&Apache::loncommon::coursebrowser_javascript($dom));
my $select_link=&Apache::loncommon::selectcourse_link('rules','courseid',
'domainid',
- 'coursename');
- my $domsel=&Apache::loncommon::select_dom_form($env{'request.role.domain'},
- 'domainid');
+ 'coursename',$dom);
+ my $syllabuslink = ''.&mt('Syllabus').' '.
+ (' 'x2).&mt('(shows course personnel)');
my $default_form_data=&defaultFormData(&get_symb($r,1));
$r->print('
+'.&mt('Send scanned bubblesheet data to a course').'
+
');
return '';
}
-=pod
-
-=item scantron_upload_scantron_data_save
-
- Adds a provided bubble information data file to the course if user
- has the correct privileges to do so.
-
-=cut
sub scantron_upload_scantron_data_save {
my($r)=@_;
@@ -7677,7 +7786,7 @@ sub scantron_upload_scantron_data_save {
if (!&Apache::lonnet::allowed('usc',$env{'form.domainid'}) &&
!&Apache::lonnet::allowed('usc',
$env{'form.domainid'}.'_'.$env{'form.courseid'})) {
- $r->print(&mt("You are not allowed to upload Scantron data to the requested course.")." ");
+ $r->print(&mt("You are not allowed to upload bubblesheet data to the requested course.")." ");
if ($symb) {
$r->print(&show_grading_menu_form($symb));
} else {
@@ -7686,36 +7795,25 @@ sub scantron_upload_scantron_data_save {
return '';
}
my %coursedata=&Apache::lonnet::coursedescription($env{'form.domainid'}.'_'.$env{'form.courseid'});
- $r->print(&mt("Doing upload to [_1]",$coursedata{'description'})." ");
- my $fname=$env{'form.upfile.filename'};
- #FIXME
- #copied from lonnet::userfileupload()
- #make that function able to target a specified course
- # Replace Windows backslashes by forward slashes
- $fname=~s/\\/\//g;
- # Get rid of everything but the actual filename
- $fname=~s/^.*\/([^\/]+)$/$1/;
- # Replace spaces by underscores
- $fname=~s/\s+/\_/g;
- # Replace all other weird characters by nothing
- $fname=~s/[^\w\.\-]//g;
- # See if there is anything left
- unless ($fname) { return 'error: no uploaded file'; }
- my $uploadedfile=$fname;
- $fname='scantron_orig_'.$fname;
+ my $uploadedfile;
+ $r->print(''.&mt("Uploading file to [_1]",$coursedata{'description'}).' ');
if (length($env{'form.upfile'}) < 2) {
- $r->print(&mt("Error: The file you attempted to upload, [_1] contained no information. Please check that you entered the correct filename.",''.&HTML::Entities::encode($env{'form.upfile.filename'},'<>&"')." "));
+ $r->print(&mt('[_1]Error:[_2] The file you attempted to upload, [_3] contained no information. Please check that you entered the correct filename.','',' ',''.&HTML::Entities::encode($env{'form.upfile.filename'},'<>&"').' '));
} else {
- my $result=&Apache::lonnet::finishuserfileupload($env{'form.courseid'},$env{'form.domainid'},'upfile',$fname);
- if ($result =~ m|^/uploaded/|) {
- $r->print(&mt("Success: Successfully uploaded [_1] bytes of data into location [_2]",
- (length($env{'form.upfile'})-1),
- ''.$result." "));
+ my $result =
+ &Apache::lonnet::userfileupload('upfile','','scantron','','','',
+ $env{'form.courseid'},$env{'form.domainid'});
+ if ($result =~ m{^/uploaded/}) {
+ $r->print(&mt('[_1]Success:[_2] Successfully uploaded [_3] bytes of data into location: [_4]',
+ '',' ',(length($env{'form.upfile'})-1),
+ ''.$result.' '));
+ ($uploadedfile) = ($result =~ m{/([^/]+)$});
+ $r->print(&validate_uploaded_scantron_file($env{'form.domainid'},
+ $env{'form.courseid'},$uploadedfile));
} else {
- $r->print(&mt("Error: An error ([_1]) occurred when attempting to upload the file, [_2]",
- $result,
- ''.&HTML::Entities::encode($env{'form.upfile.filename'},'<>&"')." "));
-
+ $r->print(&mt('[_1]Error:[_2] An error ([_3]) occurred when attempting to upload the file, [_4]',
+ '',' ',$result,
+ ''.&HTML::Entities::encode($env{'form.upfile.filename'},'<>&"').' '));
}
}
if ($symb) {
@@ -7726,13 +7824,91 @@ sub scantron_upload_scantron_data_save {
return '';
}
-=pod
-
-=item valid_file
-
- Validates that the requested bubble data file exists in the course.
-
-=cut
+sub validate_uploaded_scantron_file {
+ my ($cdom,$cname,$fname) = @_;
+ my $scanlines=&Apache::lonnet::getfile('/uploaded/'.$cdom.'/'.$cname.'/'.$fname);
+ my @lines;
+ if ($scanlines ne '-1') {
+ @lines=split("\n",$scanlines,-1);
+ }
+ my $output;
+ if (@lines) {
+ my (%counts,$max_match_format);
+ my ($max_match_count,$max_match_pct) = (0,0);
+ my $classlist = &Apache::loncoursedata::get_classlist($cdom,$cname);
+ my %idmap = &username_to_idmap($classlist);
+ foreach my $key (keys(%idmap)) {
+ my $lckey = lc($key);
+ $idmap{$lckey} = $idmap{$key};
+ }
+ my %unique_formats;
+ my @formatlines = &get_scantronformat_file();
+ foreach my $line (@formatlines) {
+ chomp($line);
+ my @config = split(/:/,$line);
+ my $idstart = $config[5];
+ my $idlength = $config[6];
+ if (($idstart ne '') && ($idlength > 0)) {
+ if (ref($unique_formats{$idstart.':'.$idlength}) eq 'ARRAY') {
+ push(@{$unique_formats{$idstart.':'.$idlength}},$config[0].':'.$config[1]);
+ } else {
+ $unique_formats{$idstart.':'.$idlength} = [$config[0].':'.$config[1]];
+ }
+ }
+ }
+ foreach my $key (keys(%unique_formats)) {
+ my ($idstart,$idlength) = split(':',$key);
+ %{$counts{$key}} = (
+ 'found' => 0,
+ 'total' => 0,
+ );
+ foreach my $line (@lines) {
+ next if ($line =~ /^#/);
+ next if ($line =~ /^[\s\cz]*$/);
+ my $id = substr($line,$idstart-1,$idlength);
+ $id = lc($id);
+ if (exists($idmap{$id})) {
+ $counts{$key}{'found'} ++;
+ }
+ $counts{$key}{'total'} ++;
+ }
+ if ($counts{$key}{'total'}) {
+ my $percent_match = (100*$counts{$key}{'found'})/($counts{$key}{'total'});
+ if (($max_match_format eq '') || ($percent_match > $max_match_pct)) {
+ $max_match_pct = $percent_match;
+ $max_match_format = $key;
+ $max_match_count = $counts{$key}{'total'};
+ }
+ }
+ }
+ if (ref($unique_formats{$max_match_format}) eq 'ARRAY') {
+ my $format_descs;
+ my $numwithformat = @{$unique_formats{$max_match_format}};
+ for (my $i=0; $i<$numwithformat; $i++) {
+ my ($name,$desc) = split(':',$unique_formats{$max_match_format}[$i]);
+ if ($i<$numwithformat-2) {
+ $format_descs .= '"'.$desc.' ", ';
+ } elsif ($i==$numwithformat-2) {
+ $format_descs .= '"'.$desc.' " '.&mt('and').' ';
+ } elsif ($i==$numwithformat-1) {
+ $format_descs .= '"'.$desc.' "';
+ }
+ }
+ my $showpct = sprintf("%.0f",$max_match_pct).'%';
+ $output .= ' '.&mt('Comparison of student IDs in the uploaded file with the course roster found matches for [_1] of the [_2] entries in the file (for the format defined for [_3]).',''.$showpct.' ',''.$max_match_count.' ',$format_descs).
+ ' '.&mt('A low percentage of matches results from one of the following:').''.
+ ''.&mt('The file was uploaded to the wrong course').' '.
+ ''.&mt('The data are not in the format expected for the domain: [_1]',
+ ''.$cdom.' ').' '.
+ ''.&mt('Students did not bubble their IDs, or mis-bubbled them').' '.
+ ''.&mt('The course roster is not up to date').' '.
+ ' ';
+ }
+ } else {
+ $output = ''.&mt('Uploaded file contained no data').' ';
+ }
+ return $output;
+}
sub valid_file {
my ($requested_file)=@_;
@@ -7742,16 +7918,6 @@ sub valid_file {
return 0;
}
-=pod
-
-=item scantron_download_scantron_data
-
- Shows a list of the three internal files (original, corrected,
- skipped) for a specific bubble sheet data file that exists in the
- course.
-
-=cut
-
sub scantron_download_scantron_data {
my ($r)=@_;
my $default_form_data=&defaultFormData(&get_symb($r,1));
@@ -7791,11 +7957,290 @@ sub scantron_download_scantron_data {
return '';
}
-=pod
+sub checkscantron_results {
+ my ($r) = @_;
+ my ($symb)=&get_symb($r);
+ if (!$symb) {return '';}
+ my $grading_menu_button=&show_grading_menu_form($symb);
+ my $cid = $env{'request.course.id'};
+ my %lettdig = &letter_to_digits();
+ my $numletts = scalar(keys(%lettdig));
+ my $cnum = $env{'course.'.$cid.'.num'};
+ my $cdom = $env{'course.'.$cid.'.domain'};
+ my (undef, undef, $sequence) = &Apache::lonnet::decode_symb($env{'form.selectpage'});
+ my %record;
+ my %scantron_config =
+ &Apache::grades::get_scantron_config($env{'form.scantron_format'});
+ my ($scanlines,$scan_data)=&Apache::grades::scantron_getfile();
+ my $classlist=&Apache::loncoursedata::get_classlist();
+ my %idmap=&Apache::grades::username_to_idmap($classlist);
+ my $navmap=Apache::lonnavmaps::navmap->new();
+ my $map=$navmap->getResourceByUrl($sequence);
+ my @resources=$navmap->retrieveResources($map,\&scantron_filter,1,0);
+ my (%grader_partids_by_symb,%grader_randomlists_by_symb);
+ &graders_resources_pass(\@resources,\%grader_partids_by_symb, \%grader_randomlists_by_symb);
-=back
+ my ($uname,$udom);
+ my (%scandata,%lastname,%bylast);
+ $r->print('
+ '.$grading_menu_button);
+ return;
+}
+
+sub verify_scantron_grading {
+ my ($resource,$domain,$username,$cid,$counter,$scandata,$partids,
+ $scantron_config,$lettdig,$numletts) = @_;
+ my ($record,%expected,%startpos);
+ return ($counter,$record) if (!ref($resource));
+ return ($counter,$record) if (!$resource->is_problem());
+ my $symb = $resource->symb();
+ return ($counter,$record) if (ref($partids) ne 'ARRAY');
+ foreach my $part_id (@{$partids}) {
+ $counter ++;
+ $expected{$part_id} = 0;
+ if ($env{"form.scantron.sub_bubblelines.$counter"}) {
+ my @sub_lines = split(/,/,$env{"form.scantron.sub_bubblelines.$counter"});
+ foreach my $item (@sub_lines) {
+ $expected{$part_id} += $item;
+ }
+ } else {
+ $expected{$part_id} = $env{"form.scantron.bubblelines.$counter"};
+ }
+ $startpos{$part_id} = $env{"form.scantron.first_bubble_line.$counter"};
+ }
+ if ($symb) {
+ my %recorded;
+ my (%returnhash) = &Apache::lonnet::restore($symb,$cid,$domain,$username);
+ if ($returnhash{'version'}) {
+ my %lasthash=();
+ my $version;
+ for ($version=1;$version<=$returnhash{'version'};$version++) {
+ foreach my $key (sort(split(/\:/,$returnhash{$version.':keys'}))) {
+ $lasthash{$key}=$returnhash{$version.':'.$key};
+ }
+ }
+ foreach my $key (keys(%lasthash)) {
+ if ($key =~ /\.scantron$/) {
+ my $value = &unescape($lasthash{$key});
+ my ($part_id) = ($key =~ /^resource\.(.+)\.scantron$/);
+ if ($value eq '') {
+ for (my $i=0; $i<$expected{$part_id}; $i++) {
+ for (my $j=0; $j<$scantron_config->{'length'}; $j++) {
+ $recorded{$part_id} .= $scantron_config->{'Qoff'};
+ }
+ }
+ } else {
+ my @tocheck;
+ my @items = split(//,$value);
+ if (($scantron_config->{'Qon'} eq 'letter') ||
+ ($scantron_config->{'Qon'} eq 'number')) {
+ if (@items < $expected{$part_id}) {
+ my $fragment = substr($scandata,$startpos{$part_id},$expected{$part_id});
+ my @singles = split(//,$fragment);
+ foreach my $pos (@singles) {
+ if ($pos eq ' ') {
+ push(@tocheck,$pos);
+ } else {
+ my $next = shift(@items);
+ push(@tocheck,$next);
+ }
+ }
+ } else {
+ @tocheck = @items;
+ }
+ foreach my $letter (@tocheck) {
+ if ($scantron_config->{'Qon'} eq 'letter') {
+ if ($letter !~ /^[A-J]$/) {
+ $letter = $scantron_config->{'Qoff'};
+ }
+ $recorded{$part_id} .= $letter;
+ } elsif ($scantron_config->{'Qon'} eq 'number') {
+ my $digit;
+ if ($letter !~ /^[A-J]$/) {
+ $digit = $scantron_config->{'Qoff'};
+ } else {
+ $digit = $lettdig->{$letter};
+ }
+ $recorded{$part_id} .= $digit;
+ }
+ }
+ } else {
+ @tocheck = @items;
+ for (my $i=0; $i<$expected{$part_id}; $i++) {
+ my $curr_sub = shift(@tocheck);
+ my $digit;
+ if ($curr_sub =~ /^[A-J]$/) {
+ $digit = $lettdig->{$curr_sub}-1;
+ }
+ if ($curr_sub eq 'J') {
+ $digit += scalar($numletts);
+ }
+ for (my $j=0; $j<$scantron_config->{'Qlength'}; $j++) {
+ if ($j == $digit) {
+ $recorded{$part_id} .= $scantron_config->{'Qon'};
+ } else {
+ $recorded{$part_id} .= $scantron_config->{'Qoff'};
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ foreach my $part_id (@{$partids}) {
+ if ($recorded{$part_id} eq '') {
+ for (my $i=0; $i<$expected{$part_id}; $i++) {
+ for (my $j=0; $j<$scantron_config->{'Qlength'}; $j++) {
+ $recorded{$part_id} .= $scantron_config->{'Qoff'};
+ }
+ }
+ }
+ $record .= $recorded{$part_id};
+ }
+ }
+ return ($counter,$record);
+}
+
+sub letter_to_digits {
+ my %lettdig = (
+ A => 1,
+ B => 2,
+ C => 3,
+ D => 4,
+ E => 5,
+ F => 6,
+ G => 7,
+ H => 8,
+ I => 9,
+ J => 0,
+ );
+ return %lettdig;
+}
-=cut
#-------- end of section for handling grading scantron forms -------
#
@@ -7842,36 +8287,49 @@ sub grading_menu {
'saveState'=>"",
'gradingMenu'=>1,
'showgrading'=>"yes");
- my $url = &Apache::lonhtmlcommon::build_url('grades/',\%fields);
- my @menu = ({ url => $url,
- name => &mt('Manual Grading/View Submissions'),
- short_description =>
- &mt('Start the process of hand grading submissions.'),
- });
+
+ my $url1 = &Apache::lonhtmlcommon::build_url('grades/',\%fields);
+
$fields{'command'} = 'csvform';
- $url = &Apache::lonhtmlcommon::build_url('grades/',\%fields);
- push (@menu, { url => $url,
- name => &mt('Upload Scores'),
- short_description =>
- &mt('Specify a file containing the class scores for current resource.')});
+ my $url2 = &Apache::lonhtmlcommon::build_url('grades/',\%fields);
+
$fields{'command'} = 'processclicker';
- $url = &Apache::lonhtmlcommon::build_url('grades/',\%fields);
- push (@menu, { url => $url,
- name => &mt('Process Clicker'),
- short_description =>
- &mt('Specify a file containing the clicker information for this resource.')});
+ my $url3 = &Apache::lonhtmlcommon::build_url('grades/',\%fields);
+
$fields{'command'} = 'scantron_selectphase';
- $url = &Apache::lonhtmlcommon::build_url('grades/',\%fields);
- push (@menu, { url => $url,
- name => &mt('Grade/Manage Scantron Forms'),
- short_description =>
- &mt('')});
- $fields{'command'} = 'verify';
- $url = &Apache::lonhtmlcommon::build_url('grades/',\%fields);
- push (@menu, { url => "",
- name => &mt('Verify Receipt'),
- short_description =>
- &mt('')});
+ my $url4 = &Apache::lonhtmlcommon::build_url('grades/',\%fields);
+
+ my @menu = ({ categorytitle=>'Course Grading',
+ items =>[
+ { linktext => 'Manual Grading/View Submissions',
+ url => $url1,
+ permission => 'F',
+ icon => 'edit-find-replace.png',
+ linktitle => 'Start the process of hand grading submissions.'
+ },
+ { linktext => 'Upload Scores',
+ url => $url2,
+ permission => 'F',
+ icon => 'uploadscores.png',
+ linktitle => 'Specify a file containing the class scores for current resource.'
+ },
+ { linktext => 'Process Clicker',
+ url => $url3,
+ permission => 'F',
+ icon => 'addClickerInfoFile.png',
+ linktitle => 'Specify a file containing the clicker information for this resource.'
+ },
+ { linktext => 'Grade/Manage/Review Scantron Forms',
+ url => $url4,
+ permission => 'F',
+ icon => 'stat.png',
+ linktitle => 'Grade scantron exams, upload/download scantron data files, and review previously graded scantron exams.'
+ }
+ ]
+ });
+
+ #$fields{'command'} = 'verify';
+ #$url = &Apache::lonhtmlcommon::build_url('grades/',\%fields);
#
# Create the menu
my $Str;
@@ -7885,25 +8343,16 @@ sub grading_menu {
' '."\n".
' '."\n";
- foreach my $menudata (@menu) {
- if ($menudata->{'name'} ne &mt('Verify Receipt')) {
- $Str .=' \n";
- } else {
- $Str .=' {'jscript'}.
- ' onClick="javascript:checkChoice(document.forms.gradingMenu,\'5\',\'verify\')" '.
- ' /> '.
- &Apache::lonnet::recprefix($env{'request.course.id'}).
- '- ';
- }
- $Str .= ' '.(' 'x8).$menudata->{'short_description'}.
- "\n";
- }
+ $Str .= Apache::lonhtmlcommon::generate_menu(@menu);
+ #$menudata->{'jscript'}
+ $Str .=' '.
+ &Apache::lonnet::recprefix($env{'request.course.id'}).
+ '- ';
+
$Str .="\n";
+ my $receiptalert = &mt("Please enter a receipt number given by a student in the receipt box.");
$request->print(<
function checkChoice(formname,val,cmdx) {
@@ -7931,7 +8380,7 @@ sub grading_menu {
if (nospace == "OK" && isNaN(receiptNo)) {checkOpt = true;}
if (nospace == "notOK" && (isNaN(receiptNo) || receiptNo == "")) {checkOpt = true;}
if (checkOpt) {
- alert("Please enter a receipt number given by a student in the receipt box.");
+ alert("$receiptalert");
formname.receipt.value = "";
formname.receipt.focus();
return false;
@@ -7952,6 +8401,7 @@ sub submit_options {
if (!$symb) {return '';}
my $probTitle = &Apache::lonnet::gettitle($symb);
+ my $receiptalert = &mt("Please enter a receipt number given by a student in the receipt box.");
$request->print(<
function checkChoice(formname,val,cmdx) {
@@ -7979,7 +8429,7 @@ sub submit_options {
if (nospace == "OK" && isNaN(receiptNo)) {checkOpt = true;}
if (nospace == "notOK" && (isNaN(receiptNo) || receiptNo == "")) {checkOpt = true;}
if (checkOpt) {
- alert("Please enter a receipt number given by a student in the receipt box.");
+ alert("$receiptalert");
formname.receipt.value = "";
formname.receipt.focus();
return false;
@@ -7998,6 +8448,15 @@ GRADINGMENUJS
my $saveSub = ($$savedState{'saveSub'} eq '' ? 'all' : $$savedState{'saveSub'});
my $saveStatus = ($$savedState{'saveStatus'} eq '' ? 'Active' : $$savedState{'saveStatus'});
+ # Preselect sections
+ my $selsec="";
+ if (ref($sections)) {
+ foreach my $section (sort(@$sections)) {
+ $selsec.=''.$section.' '."\n";
+ }
+ }
+
$result.='