'.
@@ -764,28 +699,23 @@ sub verifyreceipt {
if ($receiptparts) {
$contents.='
'.$part.'
';
}
- $contents.='
'."\n";
+ $contents.=
+ &Apache::loncommon::end_data_table_row()."\n";
$matches++;
}
}
}
if ($matches == 0) {
- $string = $title.'No match found for the above receipt.';
+ $string = $title.&mt('No match found for the above receipt.');
} else {
$string = &jscriptNform($symb).$title.
- 'The above receipt matches the following student'.
- ($matches <= 1 ? '.' : 's.')."\n".
- '
'."\n".
- '
'."\n".
- '
Fullname
'."\n".
- '
Username
'."\n".
- '
Domain
';
- if ($receiptparts) {
- $string.='
Problem Part
';
- }
- $string.='
'."\n".$contents.
- '
'."\n";
+ '
'.
+ &mt('The above receipt matches the following [numerate,_1,student].',$matches).
+ '
'.$viewgrade.
- ' Submissions for a Student or a Group of Students
';
+ my $result='
'.
+ &mt($viewgrade.' Submissions for a Student or a Group of Students')
+ .'
';
my ($table,undef,$hdgrade,$partlist,$handgrade) = &showResourceInfo($symb,$env{'form.probTitle'},($env{'form.showgrading'} eq 'yes'));
+ my %lt = ( 'multiple' =>
+ "Please select a student or group of students before clicking on the Next button.",
+ 'single' =>
+ "Please select the student before clicking on the Next button.",
+ );
+ %lt = &Apache::lonlocal::texthash(%lt);
$request->print(<
function checkSelect(checkBox) {
@@ -823,15 +760,15 @@ sub listStudents {
ctr++;
}
}
- sense = "a student or group of students";
+ sense = '$lt{'multiple'}';
} else {
if (checkBox.checked) {
ctr = 1;
}
- sense = "the student";
+ sense = '$lt{'single'}';
}
if (ctr == 0) {
- alert("Please select "+sense+" before clicking on the Next button.");
+ alert(sense);
return false;
}
document.gradesub.submit();
@@ -851,30 +788,49 @@ LISTJAVASCRIPT
my $checkhdgrade = ($env{'form.handgrade'} eq 'yes' && scalar(@$partlist) > 1 ) ? 'checked="checked"' : '';
my $checklastsub = $checkhdgrade eq '' ? 'checked="checked"' : '';
my $gradeTable=''."\n";
+ 'value="'.&mt('Next->').'" />'."\n";
if ($ctr == 0) {
my $num_students=(scalar(keys(%$fullname)));
if ($num_students eq 0) {
- $gradeTable=' There are no students currently enrolled.';
+ $gradeTable=' '.&mt('There are no students currently enrolled.').'';
} else {
my $submissions='submissions';
if ($submitonly eq 'incorrect') { $submissions = 'incorrect submissions'; }
if ($submitonly eq 'graded' ) { $submissions = 'ungraded submissions'; }
if ($submitonly eq 'queued' ) { $submissions = 'queued submissions'; }
$gradeTable=' '.
- 'No '.$submissions.' found for this resource for any students. ('.$num_students.
- ' students checked for '.$submissions.') ';
+ &mt('No '.$submissions.' found for this resource for any students. ([_1] students checked for '.$submissions.')',
+ $num_students).
+ ' ';
}
} elsif ($ctr == 1) {
$gradeTable =~ s/type="checkbox"/type="checkbox" checked="checked"/;
@@ -1080,9 +1038,9 @@ sub check_script {
}
sub check_buttons {
- my $buttons.='';
- $buttons.=' ';
- $buttons.='';
+ my $buttons.='';
+ $buttons.=' ';
+ $buttons.='';
$buttons.=' ';
return $buttons;
}
@@ -1617,8 +1575,7 @@ sub get_increment {
sub gradeBox {
my ($request,$symb,$uname,$udom,$counter,$partid,$record) = @_;
my $checkIcon = '';
+ '" src="'.&Apache::loncommon::lonhttpdurl($request->dir_config('lonIconsURL').'/check.gif').'" height="16" border="0" />';
my $wgt = &Apache::lonnet::EXT('resource.'.$partid.'.weight',$symb,$udom,$uname);
my $wgtmsg = ($wgt > 0) ? &mt('(problem weight)')
: ''.&mt('problem weight assigned by computer').'';
@@ -1633,41 +1590,47 @@ sub gradeBox {
if ($last_resets{$partid}) {
$aggtries = &get_num_tries($record,$last_resets{$partid},$partid);
}
- $result.='
'.
- 'Part: '.$display_part.' Points:
'."\n";
+ $result.='
';
my $ctr = 0;
my $thisweight = 0;
my $increment = &get_increment();
- $result.='
'."\n"; # display radio buttons in a nice table 10 across
+
+ my $radio.='
'."\n"; # display radio buttons in a nice table 10 across
while ($thisweight<=$wgt) {
- $result.= '
'."\n";
$result.=&handback_box($symb,$uname,$udom,$counter,$partid,$record);
return $result;
}
@@ -1708,7 +1670,7 @@ sub handback_box {
''.$file_disp.'');
$result.=''."\n";
$result.=' ';
- $result.='(File will be uploaded when you click on Save & Next below.) ';
+ $result.='('.&mt('File will be uploaded when you click on Save & Next below.').') ';
$file_counter++;
}
}
@@ -1854,8 +1816,8 @@ sub submission {
if ($env{'form.handgrade'} eq 'yes' && &files_exist($request, $symb)) {
&download_all_link($request, $symb);
}
- $request->print('
Submission Record
'."\n".
- '
Resource: '.$env{'form.probTitle'}.'
'."\n");
+ $request->print('
'.&mt('Submission Record').'
'."\n".
+ '
'.&mt('Resource: [_1]',$env{'form.probTitle'}).'
'."\n");
# option to display problem, only once else it cause problems
# with the form later since the problem has a form.
@@ -2220,7 +2182,7 @@ KEYWORDS
# print end of form
if ($counter == $total) {
my $endform='
'."\n";
- $endform.=' '."\n";
my $ntstu =''."\n";
my $nsel = ($env{'form.NTSTU'} ne '' ? $env{'form.NTSTU'} : '1');
$ntstu =~ s/
';
+ $endform.='';
$endform.=&show_grading_menu_form($symb);
$request->print($endform);
}
@@ -2576,9 +2538,9 @@ sub processHandGrade {
$ctr++;
}
if ($total < 0) {
- my $the_end = '
LON-CAPA User Message
'."\n";
- $the_end.='Message: No more students for this section or class.
'."\n";
- $the_end.='Click on the button below to return to the grading menu.
'."\n";
+ my $the_end = '
'.&mt('LON-CAPA User Message').'
'."\n";
+ $the_end.=&mt('Message: No more students for this section or class.').'
'."\n";
+ $the_end.=&mt('Click on the button below to return to the grading menu.').'
'."\n";
$the_end.=&show_grading_menu_form($symb);
$request->print($the_end);
}
@@ -3149,7 +3111,7 @@ sub viewgrades {
&Apache::lonnet::clear_EXT_cache_status();
my $result='
'."\n";
#view individual student submission form - called using Javascript viewOneStudent
$result.=&jscriptNform($symb);
@@ -3167,13 +3129,15 @@ sub viewgrades {
my $sectionClass;
my $section_display = join (", ",&Apache::loncommon::get_env_multiple('form.section'));
if ($env{'form.section'} eq 'all') {
- $sectionClass='Class ';
+ $sectionClass='Class';
} elsif ($env{'form.section'} eq 'none') {
- $sectionClass=&mt('Students in no Section').'';
+ $sectionClass='Students in no Section';
} else {
- $sectionClass=&mt('Students in Section(s) [_1]',$section_display).'';
+ $sectionClass='Students in Section(s) [_1]';
}
- $result.='
'.&mt('Assign Common Grade To [_1]',$sectionClass);
+ $result.=
+ '
'.
+ &mt("Assign Common Grade To $sectionClass",$section_display).'
';
$result.= &Apache::loncommon::start_data_table();
#radio buttons/text box for assigning points for a section or class.
#handles different parts of a problem
@@ -3191,48 +3155,52 @@ sub viewgrades {
my $wgt = &Apache::lonnet::EXT('resource.'.$partid.'.weight',$symb);
$weight{$partid} = $wgt eq '' ? '1' : $wgt;
- $result.=&Apache::loncommon::start_data_table_row().'
',$display_part,$radio,$line).
+ &Apache::loncommon::end_data_table_row()."\n";
$ctsparts++;
}
$result.=&Apache::loncommon::end_data_table()."\n".
'';
- $result.='';
#table listing all the students in a section/class
#header of table
- $result.= '
Assign Grade to Specific Students in '.$sectionClass;
+ $result.= '
'.&mt('Assign Grade to Specific Students in '.$sectionClass,
+ $section_display).'
'."\n";
}
$result.=&Apache::loncommon::end_data_table_header_row();
@@ -3276,14 +3251,14 @@ sub viewgrades {
}
$result.=&Apache::loncommon::end_data_table();
$result.=''."\n";
- $result.=''."\n";
if (scalar(%$fullname) eq 0) {
my $colspan=3+scalar(@parts);
my $section_display = join (", ",&Apache::loncommon::get_env_multiple('form.section'));
my $stu_status = join(' or ',&Apache::loncommon::get_env_multiple('form.Status'));
$result=''.
- &mt('There are no students in section(s) [_1] with enrollment status [_2] to modify or grade',
+ &mt('There are no students in section(s) [_1] with enrollment status [_2] to modify or grade.',
$section_display, $stu_status).
'';
}
@@ -3339,9 +3314,9 @@ sub viewstudentgrade {
$result.=' '."\n";
- $result.= (($status eq 'excused') ? ''
- : '')."\n";
- $result.='';
+ $result.= (($status eq 'excused') ? ''
+ : '')."\n";
+ $result.='';
$result.=" \n";
} else {
$result.=' '.
- 'Manual Grading by Page or Sequence
';
+ &mt('Manual Grading by Page or Sequence').'';
$result.=''."\n";
+ 'onClick="javascript:checkPickOne(this.form);" value="'.&mt('Next->').'" />'."\n";
$studentTable.=&show_grading_menu_form($symb);
$request->print($studentTable);
@@ -4179,15 +4167,16 @@ sub displayPage {
&Apache::lonnet::clear_EXT_cache_status();
if (!&canview($usec)) {
- $request->print('Unable to view requested student.('.$env{'form.student'}.')');
+ $request->print(''.&mt('Unable to view requested student. ([_1])',$env{'form.student'}).'');
$request->print(&show_grading_menu_form($symb));
return;
}
my $result='
';
+ $studentTable.=' '.&mt('Note: Problems graded correct by the computer are marked with a [_1] symbol.',$checkIcon)."\n".
+ &Apache::loncommon::start_data_table().
+ &Apache::loncommon::start_data_table_header_row().
+ '
';
my %form = ('CODE' => $env{'form.CODE'},);
if ($env{'form.vProb'} eq 'yes' ) {
@@ -4258,14 +4252,14 @@ sub displayPage {
# $request->print('match='.$1." \n");
# }
# $companswer =~ s|
|
|g;
- $studentTable.=' '.$title.' Correct answer: '.$companswer;
+ $studentTable.=' '.$title.' '.&mt('Correct answer: [_1]',$companswer);
}
my %record = &Apache::lonnet::restore($symbx,$env{'request.course.id'},$udom,$uname);
if ($env{'form.lastSub'} eq 'datesub') {
if ($record{'version'} eq '') {
- $studentTable.=' No recorded submission for this problem ';
+ $studentTable.=' '.&mt('No recorded submission for this problem.').' ';
} else {
my %responseType = ();
foreach my $partid (@{$parts}) {
@@ -4301,8 +4295,8 @@ sub displayPage {
$curRes = $iterator->next();
}
- $studentTable.='
'."\n".
- ''."\n".
+ ''.
''."\n";
$studentTable.=&show_grading_menu_form($symb);
@@ -4382,13 +4376,13 @@ sub displaySubByDates {
}
}
if (exists($$record{"$where.$partid.checkedin"})) {
- $displaySub[1].='Checked in by '.
- $$record{"$where.$partid.checkedin"}.' into slot '.
- $$record{"$where.$partid.checkedin.slot"}.
- ' ';
+ $displaySub[1].=&mt('Checked in by [_1] into slot [_2]',
+ $$record{"$where.$partid.checkedin"},
+ $$record{"$where.$partid.checkedin.slot"}).
+ ' ';
}
if (exists $$record{"$where.$partid.award"}) {
- $displaySub[1].='Part: '.$display_part.' '.
+ $displaySub[1].=''.&mt('Part:').' '.$display_part.' '.
lc($$record{"$where.$partid.award"}).' '.
$mark{$$record{"$where.$partid.solved"}}.
' ';
@@ -4450,12 +4444,14 @@ sub updateGradeByPage {
my $iterator = $navmap->getIterator($map->map_start(),
$map->map_finish());
- my $studentTable='
'.
- '
'.
- '
Prob.
'.
- '
Title
'.
- '
Previous Score
'.
- '
New Score
';
+ my $studentTable=
+ &Apache::loncommon::start_data_table().
+ &Apache::loncommon::start_data_table_header_row().
+ '
'.&mt('Prob.').'
'.
+ '
'.&mt('Title').'
'.
+ '
'.&mt('Previous Score').'
'.
+ '
'.&mt('New Score').'
'.
+ &Apache::loncommon::end_data_table_header_row();
$iterator->next(); # skip the first BEGIN_MAP
my $curRes = $iterator->next(); # for "current resource"
@@ -4468,8 +4464,12 @@ sub updateGradeByPage {
my $parts = $curRes->parts();
my $title = $curRes->compTitle();
my $symbx = $curRes->symb();
- $studentTable.='
-SCANTRONFORM
+');
my $default_form_data=&defaultFormData(&get_symb($r,1));
my $cdom= $env{'course.'.$env{'request.course.id'}.'.domain'};
my $cnum= $env{'course.'.$env{'request.course.id'}.'.num'};
- $r->print(<print('
-
-SCANTRONFORM
+ '.&Apache::loncommon::end_data_table_row().'
+ '.&Apache::loncommon::end_data_table().'
+');
}
# Chunk of the form that prompts to view a scoring office file,
# corrected file, skipped records in a file.
- $r->print(<
-
');
$r->print($grading_menu_button);
return
}
@@ -5031,7 +5079,7 @@ sub get_scantron_config {
$config{'IDstart'}=$config[5];
$config{'IDlength'}=$config[6];
$config{'Qstart'}=$config[7];
- $config{'Qlength'}=$config[8];
+ $config{'Qlength'}=$config[8];
$config{'Qoff'}=$config[9];
$config{'Qon'}=$config[10];
$config{'PaperID'}=$config[11];
@@ -5105,6 +5153,8 @@ sub username_to_idmap {
- 'answer'
'response' - new answer or 'none' if blank
'question' - the bubble line to change
+ 'questionnum' - the question identifier,
+ may include subquestion.
Returns:
$line - the modified scanline
@@ -5117,8 +5167,6 @@ sub username_to_idmap {
sub scantron_fixup_scanline {
my ($scantron_config,$scan_data,$line,$whichline,$field,$args)=@_;
-
-
if ($field eq 'ID') {
if (length($args->{'newid'}) > $$scantron_config{'IDlength'}) {
return ($line,1,'New value too large');
@@ -5149,52 +5197,28 @@ sub scantron_fixup_scanline {
$$scantron_config{'CODElength'})=$args->{'CODE'};
}
} elsif ($field eq 'answer') {
- &scantron_get_maxbubble(); # Need the bubble counter info.
my $length=$scantron_config->{'Qlength'};
my $off=$scantron_config->{'Qoff'};
my $on=$scantron_config->{'Qon'};
my $answer=${off}x$length;
- my $question_number = $args->{'question'} -1;
- my $first_position = $first_bubble_line{$question_number};
- my $bubble_count = $bubble_lines_per_response{$question_number};
- my $bubbles_per_line= $$scantron_config{'Qlength'};
- my $final_answer;
- if ($$scantron_config{'Qon'} eq 'letter' ||
- $$scantron_config{'Qon'} eq 'number') {
- $bubbles_per_line = 10;
- }
- if (defined $args->{'response'}) {
-
- if ($args->{'response'} eq 'none') {
- &scan_data($scan_data,
- "$whichline.no_bubble.".$args->{'question'},'1');
+ if ($args->{'response'} eq 'none') {
+ &scan_data($scan_data,
+ "$whichline.no_bubble.".$args->{'questionnum'},'1');
+ } else {
+ if ($on eq 'letter') {
+ my @alphabet=('A'..'Z');
+ $answer=$alphabet[$args->{'response'}];
+ } elsif ($on eq 'number') {
+ $answer=$args->{'response'}+1;
+ if ($answer == 10) { $answer = '0'; }
} else {
- my ($bubble_line, $bubble_number) = split(/:/,$args->{'response'});
- if ($on eq 'letter') {
- my @alphabet=('A'..'Z');
- $answer=$alphabet[$bubble_number];
- } elsif ($on eq 'number') {
- $answer=$args->$bubble_number+1;
- if ($answer == 10) { $answer = '0'; }
- } else {
- substr($answer,$args->{'response'},1)=$on;
- }
- &scan_data($scan_data,
- "$whichline.no_bubble.".$args->{'question'},undef,'1');
- for (my $l = 0; $l < $bubble_count; $l++) {
- if ($l eq $bubble_line) {
- $final_answer .= $answer;
- } else {
- $final_answer .= ' ';
- }
- }
+ substr($answer,$args->{'response'},1)=$on;
}
- # $where=$length*($args->{'question'}-1)+$scantron_config->{'Qstart'};
- #substr($line,$where-1,$length)=$answer;
- substr($line,
- $scantron_config->{'Qstart'}+$first_position-1,
- $bubbles_per_line) = $final_answer;
+ &scan_data($scan_data,
+ "$whichline.no_bubble.".$args->{'questionnum'},undef,'1');
}
+ my $where=$length*($args->{'question'}-1)+$scantron_config->{'Qstart'};
+ substr($line,$where-1,$length)=$answer;
}
return $line;
}
@@ -5228,6 +5252,39 @@ sub scan_data {
return $scan_data->{$filename.'_'.$key};
}
+# ----- These first few routines are general use routines.----
+
+# Return the number of occurences of a pattern in a string.
+
+sub occurence_count {
+ my ($string, $pattern) = @_;
+
+ my @matches = ($string =~ /$pattern/g);
+
+ return scalar(@matches);
+}
+
+
+# Take a string known to have digits and convert all the
+# digits into letters in the range J,A..I.
+
+sub digits_to_letters {
+ my ($input) = @_;
+
+ my @alphabet = ('J', 'A'..'I');
+
+ my @input = split(//, $input);
+ my $output ='';
+ for (my $i = 0; $i < scalar(@input); $i++) {
+ if ($input[$i] =~ /\d/) {
+ $output .= $alphabet[$input[$i]];
+ } else {
+ $output .= $input[$i];
+ }
+ }
+ return $output;
+}
+
=pod
=item scantron_parse_scanline
@@ -5330,163 +5387,208 @@ sub scantron_parse_scanline {
$questions =~ s/\r$//; # Get rid of trailing \r too (MAC or Win uploads).
while (length($questions)) {
my $answers_needed = $bubble_lines_per_response{$questnum};
- my $answer_length = $$scantron_config{'Qlength'} * $answers_needed;
-
-
-
- $questnum++;
- my $currentquest = substr($questions,0,$answer_length);
- $questions = substr($questions,0,$answer_length)='';
- if (length($currentquest) < $answer_length) { next; }
-
- # Qon letter implies for each slot in currentquest we have:
- # ? or * for doubles a letter in A-Z for a bubble and
- # about anything else (esp. a value of Qoff for missing
- # bubbles.
-
-
- if ($$scantron_config{'Qon'} eq 'letter') {
-
- if ($currentquest =~ /\?/
- || $currentquest =~ /\*/
- || (&occurence_count($currentquest, "[A-Z]") > 1)) {
- push(@{$record{'scantron.doubleerror'}},$questnum);
- for (my $ans = 0; $ans < $answers_needed; $ans++) {
- my $bubble = substr($currentquest, $ans, 1);
- if ($bubble =~ /[A-Z]/ ) {
- $record{"scantron.$ansnum.answer"} = $bubble;
- } else {
- $record{"scantron.$ansnum.answer"}='';
- }
- $ansnum++;
- }
-
- } elsif (!defined($currentquest)
- || (&occurence_count($currentquest, $$scantron_config{'Qoff'}) == length($currentquest))
- || (&occurence_count($currentquest, "[A-Z]") == 0)) {
- for (my $ans = 0; $ans < $answers_needed; $ans++ ) {
- $record{"scantron.$ansnum.answer"}='';
- $ansnum++;
-
- }
- if (!&scan_data($scan_data,"$whichline.no_bubble.$questnum")) {
- push(@{$record{"scantron.missingerror"}},$questnum);
- # $ansnum += $answers_needed;
- }
- } else {
- for (my $ans = 0; $ans < $answers_needed; $ans++) {
- $record{"scantron.$ansnum.answer"} = substr($currentquest, $ans, 1);
- $ansnum++;
- }
- }
-
- # Qon 'number' implies each slot gives a digit that indexes the
- # the bubbles filled or Qoff or a non number for unbubbled lines.
- # and *? for double bubbles on a line.
- # these answers are also stored as letters.
-
- } elsif ($$scantron_config{'Qon'} eq 'number') {
- if ($currentquest =~ /\?/
- || $currentquest =~ /\*/
- || (&occurence_count($currentquest, '\d') > 1)) {
- push(@{$record{'scantron.doubleerror'}},$questnum);
- for (my $ans = 0; $ans < $answers_needed; $ans++) {
- my $bubble = substr($currentquest, $ans, 1);
- if ($bubble =~ /\d/) {
- $record{"scantron.$ansnum.answer"} = $alphabet[$bubble];
- } else {
- $record{"scantron.$ansnum.answer"}=' ';
- }
- $ansnum++;
- }
-
- } elsif (!defined($currentquest)
- || (&occurence_count($currentquest,$$scantron_config{'Qoff'}) == length($currentquest))
- || (&occurence_count($currentquest, '\d') == 0)) {
- for (my $ans = 0; $ans < $answers_needed; $ans++ ) {
- $record{"scantron.$ansnum.answer"}='';
- $ansnum++;
-
- }
- if (!&scan_data($scan_data,"$whichline.no_bubble.$questnum")) {
- push(@{$record{"scantron.missingerror"}},$questnum);
- $ansnum += $answers_needed;
- }
+ my $answer_length = ($$scantron_config{'Qlength'} * $answers_needed)
+ || 1;
+ $questnum++;
+ my $quest_id = $questnum;
+ my $currentquest = substr($questions,0,$answer_length);
+ $questions = substr($questions,$answer_length);
+ if (length($currentquest) < $answer_length) { next; }
+
+ if ($subdivided_bubble_lines{$questnum-1} =~ /,/) {
+ my $subquestnum = 1;
+ my $subquestions = $currentquest;
+ my @subanswers_needed =
+ split(/,/,$subdivided_bubble_lines{$questnum-1});
+ foreach my $subans (@subanswers_needed) {
+ my $subans_length =
+ ($$scantron_config{'Qlength'} * $subans) || 1;
+ my $currsubquest = substr($subquestions,0,$subans_length);
+ $subquestions = substr($subquestions,$subans_length);
+ $quest_id = "$questnum.$subquestnum";
+ if (($$scantron_config{'Qon'} eq 'letter') ||
+ ($$scantron_config{'Qon'} eq 'number')) {
+ $ansnum = &scantron_validator_lettnum($ansnum,
+ $questnum,$quest_id,$subans,$currsubquest,$whichline,
+ \@alphabet,\%record,$scantron_config,$scan_data);
+ } else {
+ $ansnum = &scantron_validator_positional($ansnum,
+ $questnum,$quest_id,$subans,$currsubquest,$whichline, \@alphabet,\%record,$scantron_config,$scan_data);
+ }
+ $subquestnum ++;
+ }
+ } else {
+ if (($$scantron_config{'Qon'} eq 'letter') ||
+ ($$scantron_config{'Qon'} eq 'number')) {
+ $ansnum = &scantron_validator_lettnum($ansnum,$questnum,
+ $quest_id,$answers_needed,$currentquest,$whichline,
+ \@alphabet,\%record,$scantron_config,$scan_data);
+ } else {
+ $ansnum = &scantron_validator_positional($ansnum,$questnum,
+ $quest_id,$answers_needed,$currentquest,$whichline,
+ \@alphabet,\%record,$scantron_config,$scan_data);
+ }
+ }
+ }
+ $record{'scantron.maxquest'}=$questnum;
+ return \%record;
+}
- } else {
- $currentquest = &digits_to_letters($currentquest);
- for (my $ans =0; $ans < $answers_needed; $ans++) {
- $record{"scantron.$ansnum.answer"} = substr($currentquest, $ans, 1);
- $ansnum++;
- }
- }
- } else {
+sub scantron_validator_lettnum {
+ my ($ansnum,$questnum,$quest_id,$answers_needed,$currquest,$whichline,
+ $alphabet,$record,$scantron_config,$scan_data) = @_;
+
+ # Qon 'letter' implies for each slot in currquest we have:
+ # ? or * for doubles, a letter in A-Z for a bubble, and
+ # about anything else (esp. a value of Qoff) for missing
+ # bubbles.
+ #
+ # Qon 'number' implies each slot gives a digit that indexes the
+ # bubbles filled, or Qoff, or a non-number for unbubbled lines,
+ # and * or ? for double bubbles on a single line.
+ #
- # Otherwise there's a positional notation;
- # each bubble line requires Qlength items, and there are filled in
- # bubbles for each case where there 'Qon' characters.
- #
+ my $matchon;
+ if ($$scantron_config{'Qon'} eq 'letter') {
+ $matchon = '[A-Z]';
+ } elsif ($$scantron_config{'Qon'} eq 'number') {
+ $matchon = '\d';
+ }
+ my $occurrences = 0;
+ if (($responsetype_per_response{$questnum-1} eq 'essayresponse') ||
+ ($responsetype_per_response{$questnum-1} eq 'formularesponse') ||
+ ($responsetype_per_response{$questnum-1} eq 'stringresponse')) {
+ my @singlelines = split('',$currquest);
+ foreach my $entry (@singlelines) {
+ $occurrences = &occurence_count($entry,$matchon);
+ if ($occurrences > 1) {
+ last;
+ }
+ }
+ } else {
+ $occurrences = &occurence_count($currquest,$matchon);
+ }
+ if (($currquest =~ /\?/ || $currquest =~ /\*/) || ($occurrences > 1)) {
+ push(@{$record->{'scantron.doubleerror'}},$quest_id);
+ for (my $ans=0; $ans<$answers_needed; $ans++) {
+ my $bubble = substr($currquest,$ans,1);
+ if ($bubble =~ /$matchon/ ) {
+ if ($$scantron_config{'Qon'} eq 'number') {
+ if ($bubble == 0) {
+ $bubble = 10;
+ }
+ $record->{"scantron.$ansnum.answer"} =
+ $alphabet->[$bubble-1];
+ } else {
+ $record->{"scantron.$ansnum.answer"} = $bubble;
+ }
+ } else {
+ $record->{"scantron.$ansnum.answer"}='';
+ }
+ $ansnum++;
+ }
+ } elsif (!defined($currquest)
+ || (&occurence_count($currquest, $$scantron_config{'Qoff'}) == length($currquest))
+ || (&occurence_count($currquest,$matchon) == 0)) {
+ for (my $ans=0; $ans<$answers_needed; $ans++ ) {
+ $record->{"scantron.$ansnum.answer"}='';
+ $ansnum++;
+ }
+ if (!&scan_data($scan_data,"$whichline.no_bubble.$quest_id")) {
+ push(@{$record->{'scantron.missingerror'}},$quest_id);
+ }
+ } else {
+ if ($$scantron_config{'Qon'} eq 'number') {
+ $currquest = &digits_to_letters($currquest);
+ }
+ for (my $ans=0; $ans<$answers_needed; $ans++) {
+ my $bubble = substr($currquest,$ans,1);
+ $record->{"scantron.$ansnum.answer"} = $bubble;
+ $ansnum++;
+ }
+ }
+ return $ansnum;
+}
- my @array=split($$scantron_config{'Qon'},$currentquest,-1);
+sub scantron_validator_positional {
+ my ($ansnum,$questnum,$quest_id,$answers_needed,$currquest,
+ $whichline,$alphabet,$record,$scantron_config,$scan_data) = @_;
- # If the split only giveas us one element.. the full length of the
- # answser string, no bubbles are filled in:
+ # Otherwise there's a positional notation;
+ # each bubble line requires Qlength items, and there are filled in
+ # bubbles for each case where there 'Qon' characters.
+ #
- if (length($array[0]) eq $$scantron_config{'Qlength'}*$answers_needed) {
- for (my $ans = 0; $ans < $answers_needed; $ans++ ) {
- $record{"scantron.$ansnum.answer"}='';
- $ansnum++;
+ my @array=split($$scantron_config{'Qon'},$currquest,-1);
- }
- if (!&scan_data($scan_data,"$whichline.no_bubble.$questnum")) {
- push(@{$record{"scantron.missingerror"}},$questnum);
- }
- } elsif (scalar(@array) lt 2) {
+ # If the split only gives us one element.. the full length of the
+ # answer string, no bubbles are filled in:
- my $location = length($array[0]);
- my $line_num = $location / $$scantron_config{'Qlength'};
- my $bubble = $alphabet[$location % $$scantron_config{'Qlength'}];
+ if (length($array[0]) eq $$scantron_config{'Qlength'}*$answers_needed) {
+ for (my $ans=0; $ans<$answers_needed; $ans++ ) {
+ $record->{"scantron.$ansnum.answer"}='';
+ $ansnum++;
+ }
+ if (!&scan_data($scan_data,"$whichline.no_bubble.$quest_id")) {
+ push(@{$record->{"scantron.missingerror"}},$quest_id);
+ }
+ } elsif (scalar(@array) == 2) {
+ my $location = length($array[0]);
+ my $line_num = int($location / $$scantron_config{'Qlength'});
+ my $bubble = $alphabet->[$location % $$scantron_config{'Qlength'}];
+ for (my $ans=0; $ans<$answers_needed; $ans++) {
+ if ($ans eq $line_num) {
+ $record->{"scantron.$ansnum.answer"} = $bubble;
+ } else {
+ $record->{"scantron.$ansnum.answer"} = ' ';
+ }
+ $ansnum++;
+ }
+ } else {
+ # If there's more than one instance of a bubble character
+ # That's a double bubble; with positional notation we can
+ # record all the bubbles filled in as well as the
+ # fact this response consists of multiple bubbles.
+ #
+ if (($responsetype_per_response{$questnum-1} eq 'essayresponse') ||
+ ($responsetype_per_response{$questnum-1} eq 'formularesponse') ||
+ ($responsetype_per_response{$questnum-1} eq 'stringresponse')) {
+ my $doubleerror = 0;
+ while (($currquest >= $$scantron_config{'Qlength'}) &&
+ (!$doubleerror)) {
+ my $currline = substr($currquest,0,$$scantron_config{'Qlength'});
+ $currquest = substr($currquest,$$scantron_config{'Qlength'});
+ my @currarray = split($$scantron_config{'Qon'},$currline,-1);
+ if (length(@currarray) > 2) {
+ $doubleerror = 1;
+ }
+ }
+ if ($doubleerror) {
+ push(@{$record->{'scantron.doubleerror'}},$quest_id);
+ }
+ } else {
+ push(@{$record->{'scantron.doubleerror'}},$quest_id);
+ }
+ my $item = $ansnum;
+ for (my $ans=0; $ans<$answers_needed; $ans++) {
+ $record->{"scantron.$item.answer"} = '';
+ $item ++;
+ }
- for (my $ans = 0; $ans < $answers_needed; $ans++) {
- if ($ans eq $line_num) {
- $record{"scantron.$ansnum.answer"} = $bubble;
- } else {
- $record{"scantron.$ansnum.answer"} = ' ';
- }
- $ansnum++;
- }
- }
- # If there's more than one instance of a bubble character
- # That's a double bubble; with positional notation we can
- # record all the bubbles filled in as well as the
- # fact this response consists of multiple bubbles.
- #
- else {
- push(@{$record{'scantron.doubleerror'}},$questnum);
-
- my $first_answer = $ansnum;
- for (my $ans =0; $ans < $answers_needed; $ans++) {
- my $item = $first_answer+$ans;
- $record{"scantron.$item.answer"} = '';
- }
-
- my @ans=@array;
- my $i=0;
- my $increment = 0;
- while ($#ans) {
- $i+=length($ans[0]) + $increment;
- my $line = int($i/$$scantron_config{'Qlength'} + $first_answer);
- my $bubble = $i%$$scantron_config{'Qlength'};
- $record{"scantron.$line.answer"}.=$alphabet[$bubble];
- shift(@ans);
- $increment = 1;
- }
- $ansnum += $answers_needed;
- }
- }
+ my @ans=@array;
+ my $i=0;
+ my $increment = 0;
+ while ($#ans) {
+ $i+=length($ans[0]) + $increment;
+ my $line = int($i/$$scantron_config{'Qlength'} + $ansnum);
+ my $bubble = $i%$$scantron_config{'Qlength'};
+ $record->{"scantron.$line.answer"}.=$alphabet->[$bubble];
+ shift(@ans);
+ $increment = 1;
+ }
+ $ansnum += $answers_needed;
}
- $record{'scantron.maxquest'}=$questnum;
- return \%record;
+ return $ansnum;
}
=pod
@@ -5626,7 +5728,8 @@ sub scantron_process_corrections {
&scantron_fixup_scanline(\%scantron_config,$scan_data,$line,
$which,'answer',
{ 'question'=>$question,
- 'response'=>$env{"form.scantron_correct_Q_$question"}});
+ 'response'=>$env{"form.scantron_correct_Q_$question"},
+ 'questionnum'=>$env{"form.scantron_questionnum_Q_$question"}});
if ($err) { last; }
}
}
@@ -5731,7 +5834,7 @@ sub remember_current_skipped {
sub check_for_error {
my ($r,$result)=@_;
if ($result ne 'ok' && $result ne 'not_found' ) {
- $r->print("An error occurred ($result) when trying to Remove the existing corrections.");
+ $r->print(&mt("An error occurred ([_1]) when trying to remove the existing corrections.",$result));
}
}
@@ -5755,25 +5858,25 @@ sub scantron_warning_screen {
$CODElist=$env{'form.scantron_CODElist'};
if ($env{'form.scantron_CODElist'} eq '') { $CODElist='None'; }
$CODElist=
- '
List of CODES to validate against:
'.
+ '
'.&mt('List of CODES to validate against:').'
'.
$env{'form.scantron_CODElist'}.'
';
}
- return (<
-Please double check the information
- below before clicking on '$button_text'
+
+'.&mt('Please double check the information below before clicking on \'[_1]\'',&mt($button_text)).'
-
Sequence to be Graded:
$title
-
Data File that will be used:
$env{'form.scantron_selectfile'}
-$CODElist
+
'.&mt('Sequence to be Graded:').'
'.$title.'
+
'.&mt('Data File that will be used:').'
'.$env{'form.scantron_selectfile'}.'
+'.$CODElist.'
-
If this information is correct, please click on '$button_text'.
-
If something is incorrect, please click the 'Grading Menu' button to start over.
+
'.&mt('If this information is correct, please click on \'[_1]\'.',&mt($button_text)).'
+
'.&mt('If something is incorrect, please click the \'Grading Menu\' button to start over.').'
');$r->rflush();
#get the student pick code ready
$r->print(&Apache::loncommon::studentbrowser_javascript());
my $max_bubble=&scantron_get_maxbubble();
@@ -5909,7 +6016,7 @@ sub scantron_validate_file {
my $stop=0;
while (!$stop && $currentphase < scalar(@validate_phases)) {
- $r->print("
Validating ".$validate_phases[$currentphase]."
");
+ $r->print(&mt('Validating '.$validate_phases[$currentphase]).' ');
$r->rflush();
my $which="scantron_validate_".$validate_phases[$currentphase];
{
@@ -5919,12 +6026,12 @@ sub scantron_validate_file {
}
if (!$stop) {
my $warning=&scantron_warning_screen('Start Grading');
- $r->print(<
-$warning
-
+ $r->print('
+'.&mt('Validation process complete.').'
+'.$warning.'
+
-STUFF
+');
} else {
$r->print('');
@@ -5932,15 +6039,19 @@ STUFF
}
if ($stop) {
if ($validate_phases[$currentphase] eq 'sequence') {
- $r->print('');
- $r->print(' this error ');
+ $r->print('');
+ $r->print(' '.&mt('this error').' ');
- $r->print("
Or click the 'Grading Menu' button to start over.
");
+ $r->print("
".&mt("Or click the 'Grading Menu' button to start over.")."
");
} else {
- $r->print('');
- $r->print(' using corrected info ');
- $r->print("");
- $r->print(" this scanline saving it for later.");
+ if ($validate_phases[$currentphase] eq 'doublebubble' || $validate_phases[$currentphase] eq 'missingbubbles') {
+ $r->print('');
+ } else {
+ $r->print('');
+ }
+ $r->print(' '.&mt('using corrected info').' ');
+ $r->print("");
+ $r->print(" ".&mt("this scanline saving it for later."));
}
}
$r->print(" ".&show_grading_menu_form($symb));
@@ -6001,7 +6112,10 @@ sub scantron_remove_scan_data {
}
my $result;
if (@todelete) {
- $result=&Apache::lonnet::del('nohist_scantrondata',\@todelete,$cdom,$cname);
+ $result = &Apache::lonnet::del('nohist_scantrondata',
+ \@todelete,$cdom,$cname);
+ } else {
+ $result = 'ok';
}
return $result;
}
@@ -6416,35 +6530,40 @@ sub scantron_validate_ID {
sub scantron_get_correction {
my ($r,$i,$scan_record,$scan_config,$line,$error,$arg)=@_;
-
#FIXME in the case of a duplicated ID the previous line, probably need
#to show both the current line and the previous one and allow skipping
#the previous one or the current one
- $r->print("
An error was detected ($error)");
if ( $$scan_record{'scantron.PaperID'} =~ /\S/) {
- $r->print(" for PaperID ".
- $$scan_record{'scantron.PaperID'}." \n");
+ $r->print("
".&mt("An error was detected ($error)".
+ " for PaperID [_1]",
+ $$scan_record{'scantron.PaperID'})."
\n");
} else {
- $r->print(" in scanline $i
".
- $line."
\n");
- }
- my $message="
The ID on the form is ".
- $$scan_record{'scantron.ID'}." \n".
- "The name on the paper is ".
- $$scan_record{'scantron.LastName'}.",".
- $$scan_record{'scantron.FirstName'}."
";
+ $r->print("
".&mt("An error was detected ($error)".
+ " in scanline [_1]
[_2]
",
+ $i,$line)." \n");
+ }
+ my $message="
".&mt("The ID on the form is [_1] ".
+ "The name on the paper is [_2],[_3]",
+ $$scan_record{'scantron.ID'},
+ $$scan_record{'scantron.LastName'},
+ $$scan_record{'scantron.FirstName'})."
";
$r->print(''."\n");
$r->print(''."\n");
+ # Array populated for doublebubble or
+ my @lines_to_correct; # missingbubble errors to build javascript
+ # to validate radio button checking
+
if ($error =~ /ID$/) {
if ($error eq 'incorrectID') {
- $r->print("The encoded ID is not in the classlist\n");
+ $r->print("
".&mt("The encoded ID is not in the classlist").
+ "
\n");
} elsif ($error eq 'duplicateID') {
- $r->print("The encoded ID has also been used by a previous paper $arg\n");
+ $r->print("
".&mt("The encoded ID has also been used by a previous paper [_1]",$arg)."
\n");
}
$r->print($message);
- $r->print("
How should I handle this? \n");
+ $r->print("
".&mt("How should I handle this?")." \n");
$r->print("\n
");
#FIXME it would be nice if this sent back the user ID and
#could do partial userID matches
@@ -6457,14 +6576,14 @@ sub scantron_get_correction {
$r->print('
The encoded CODE has also been used by a previous paper ".join(', ',@{$arg}).", and CODEs are supposed to be unique
\n");
+ $r->print("
".&mt("The encoded CODE has also been used by a previous paper [_1], and CODEs are supposed to be unique.",join(', ',@{$arg}))."
\n");
}
- $r->print("
The CODE on the form is '".
- $$scan_record{'scantron.CODE'}."' \n");
+ $r->print("
".&mt("The CODE on the form is '[_1]'",
+ $$scan_record{'scantron.CODE'})." \n");
$r->print($message);
- $r->print("
How should I handle this? \n");
+ $r->print("
".&mt("How should I handle this?")." \n");
$r->print("\n ");
my $i=0;
if ($error eq 'incorrectCODE'
@@ -6474,7 +6593,13 @@ sub scantron_get_correction {
foreach my $testcode (@{$closest}) {
my $checked='';
if (!$i) { $checked=' checked="checked" '; }
- $r->print(" Use the similar CODE ".$testcode." instead.");
+ $r->print("
+
+
+ ".&mt("Use the similar CODE [_1] instead.",
+ "".$testcode."")."
+
+ ");
$r->print("\n ");
$i++;
}
@@ -6482,7 +6607,12 @@ sub scantron_get_correction {
}
if ($$scan_record{'scantron.CODE'}=~/\S/ ) {
my $checked; if (!$i) { $checked=' checked="checked" '; }
- $r->print(" Use the CODE ".$$scan_record{'scantron.CODE'}." that is was on the paper, ignoring the error.");
+ $r->print("
+
+
+ ".&mt("Use the CODE [_1] that is was on the paper, ignoring the error.",
+ "".$$scan_record{'scantron.CODE'}."")."
+ ");
$r->print("\n ");
}
@@ -6504,118 +6634,270 @@ ENDSCRIPT
"&curCODE=".&escape($$scan_record{'scantron.CODE'}).
"&scantron_selectfile=".&escape($env{'form.scantron_selectfile'});
if ($env{'form.scantron_CODElist'} =~ /\S/) {
- $r->print("Select a CODE from the list of all CODEs and use it. Selected CODE is ");
+ $r->print("
+
+
+ ".&mt("[_1]Select[_2] a CODE from the list of all CODEs and use it.",
+ "","")."
+
+ ".&mt("Selected CODE is [_1]",""));
$r->print("\n ");
}
- $r->print(" Use as the CODE.");
+ $r->print("
+
+
+ ".&mt("Use [_1] as the CODE.",
+ ""));
$r->print("\n
There have been multiple bubbles scanned for a some question(s)
\n");
+ $r->print("
".&mt("There have been multiple bubbles scanned for some question(s)")."
\n");
+
+ # The form field scantron_questions is acutally a list of line numbers.
+ # represented by this form so:
+
+ my $line_list = &questions_to_line_list($arg);
+
$r->print('');
+ $line_list.'" />');
$r->print($message);
- $r->print("
Please indicate which bubble should be used for grading
");
+ $r->print("
".&mt("Please indicate which bubble should be used for grading")."
There have been no bubbles scanned for some question(s)
\n");
+ $r->print("
".&mt("There have been no bubbles scanned for some question(s)")."
\n");
$r->print($message);
- $r->print("
Please indicate which bubble should be used for grading
");
- $r->print("Some questions have no scanned bubbles\n");
+ $r->print("
".&mt("Please indicate which bubble should be used for grading.")."
");
+ $r->print(&mt("Some questions have no scanned bubbles.")."\n");
+
+ # The form field scantron_questions is actually a list of line numbers not
+ # a list of question numbers. Therefore:
+ #
+
+ my $line_list = &questions_to_line_list($arg);
+
$r->print('');
+ $line_list.'" />');
foreach my $question (@{$arg}) {
- my $selected = &get_response_bubbles($scan_record, $question);
- my @select_array = split(/:/,$selected); # ought to be an array of empties.
- &scantron_bubble_selector($r,$scan_config,$question, @select_array);
+ my @linenums = &prompt_for_corrections($r,$question,$scan_config,
+ $scan_record, $error);
+ push (@lines_to_correct,@linenums);
}
+ $r->print(&verify_bubbles_checked(@lines_to_correct));
} else {
$r->print("\n
");
}
$r->print("\n
");
+}
+sub verify_bubbles_checked {
+ my (@ansnums) = @_;
+ my $ansnumstr = join('","',@ansnums);
+ my $warning = &mt("A bubble or 'No bubble' selection has not been made for one or more lines.");
+ my $output = (<
+function verify_bubble_radio(form) {
+ var ansnumArray = new Array ("$ansnumstr");
+ var need_bubble_count = 0;
+ for (var i=0; i 1) {
+ var bubble_picked = 0;
+ for (var j=0; j
+ENDSCRIPT
+ return $output;
}
=pod
-=item scantron_bubble_selector
-
- Generates the html radiobuttons to correct a single bubble line
- possibly showing the existing the selected bubbles if known
+=item questions_to_line_list
- Arguments:
- $r - Apache request object
- $scan_config - hash from &get_scantron_config()
- $quest - number of the bubble line to make a corrector for
- @lines - array of answer lines.
+Converts a list of questions into a string of comma separated
+line numbers in the answer sheet used by the questions. This is
+used to fill in the scantron_questions form field.
-=cut
+ Arguments:
+ questions - Reference to an array of questions.
-sub scantron_bubble_selector {
- my ($r,$scan_config,$quest,@lines)=@_;
- my $max=$$scan_config{'Qlength'};
+=cut
- my $scmode=$$scan_config{'Qon'};
+sub questions_to_line_list {
+ my ($questions) = @_;
+ my @lines;
+
+ foreach my $item (@{$questions}) {
+ my $question = $item;
+ my ($first,$count,$last);
+ if ($item =~ /^(\d+)\.(\d+)$/) {
+ $question = $1;
+ my $subquestion = $2;
+ $first = $first_bubble_line{$question-1} + 1;
+ my @subans = split(/,/,$subdivided_bubble_lines{$question-1});
+ my $subcount = 1;
+ while ($subcount<$subquestion) {
+ $first += $subans[$subcount-1];
+ $subcount ++;
+ }
+ $count = $subans[$subquestion-1];
+ } else {
+ $first = $first_bubble_line{$question-1} + 1;
+ $count = $bubble_lines_per_response{$question-1};
+ }
+ my $last = $first+$count-1;
+ push(@lines, ($first..$last));
+ }
+ return join(',', @lines);
+}
- my $bubble_length = scalar(@lines);
+=pod
+=item prompt_for_corrections
- if ($scmode eq 'number' || $scmode eq 'letter') { $max=10; }
+Prompts for a potentially multiline correction to the
+user's bubbling (factors out common code from scantron_get_correction
+for multi and missing bubble cases).
- my $response = $quest-1;
- my $lines = $bubble_lines_per_response{$response};
+ Arguments:
+ $r - Apache request object.
+ $question - The question number to prompt for.
+ $scan_config - The scantron file configuration hash.
+ $scan_record - Reference to the hash that has the the parsed scanlines.
+ $error - Type of error
+
+ Implicit inputs:
+ %bubble_lines_per_response - Starting line numbers for each question.
+ Numbered from 0 (but question numbers are from
+ 1.
+ %first_bubble_line - Starting bubble line for each question.
+ %subdivided_bubble_lines - optionresponse and matchresponse type
+ problems render as separate sub-questions,
+ in exam mode. This hash contains a
+ comma-separated list of the lines per
+ sub-question.
+ %responsetype_per_response - essayresponse, forumalaresponse, and
+ stringresponse type problem parts can have
+ multiple lines per response if the weight
+ assigned exceeds 10. In this case, only
+ one bubble per line is permitted, but more
+ than one line might contain bubbles, e.g.
+ bubbling of: line 1 - J, line 2 - J,
+ line 3 - B would assign 22 points.
- my $total_lines = $lines*2;
- my @alphabet=('A'..'Z');
+=cut
- $r->print("
$quest
");
+sub prompt_for_corrections {
+ my ($r, $question, $scan_config, $scan_record, $error) = @_;
+ my ($current_line,$lines);
+ my @linenums;
+ my $questionnum = $question;
+ if ($question =~ /^(\d+)\.(\d+)$/) {
+ $question = $1;
+ $current_line = $first_bubble_line{$question-1} + 1 ;
+ my $subquestion = $2;
+ my @subans = split(/,/,$subdivided_bubble_lines{$question-1});
+ my $subcount = 1;
+ while ($subcount<$subquestion) {
+ $current_line += $subans[$subcount-1];
+ $subcount ++;
+ }
+ $lines = $subans[$subquestion-1];
+ } else {
+ $current_line = $first_bubble_line{$question-1} + 1 ;
+ $lines = $bubble_lines_per_response{$question-1};
+ }
+ if ($lines > 1) {
+ $r->print(&mt('The group of bubble lines below responds to a single question.').' ');
+ if (($responsetype_per_response{$question-1} eq 'essayresponse') ||
+ ($responsetype_per_response{$question-1} eq 'formularesponse') ||
+ ($responsetype_per_response{$question-1} eq 'stringresponse')) {
+ $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'.").'
');
+ } else {
+ $r->print(&mt("Select at most one bubble in a single line and select 'No Bubble' in all the other lines. ")." ");
+ }
+ }
+ for (my $i =0; $i < $lines; $i++) {
+ my $selected = $$scan_record{"scantron.$current_line.answer"};
+ &scantron_bubble_selector($r,$scan_config,$current_line,
+ $questionnum,$error,split('', $selected));
+ push (@linenums,$current_line);
+ $current_line++;
+ }
+ if ($lines > 1) {
+ $r->print(" ");
+ }
+ return @linenums;
+}
- for (my $l = 0; $l < $lines; $l++) {
- if ($l != 0) {
- $r->print('
');
- }
- my @selected = split(//,$lines[$l]);
- for (my $i=0;$i<$max;$i++) {
- $r->print("\n".'
');
-
- }
+=pod
- if ($l == 0) {
- my $lspan = $total_lines * 2; # 2 table rows per bubble line.
+=item scantron_bubble_selector
+
+ Generates the html radiobuttons to correct a single bubble line
+ possibly showing the existing the selected bubbles if known
- $r->print('
No bubble
');
-
- }
+ Arguments:
+ $r - Apache request object
+ $scan_config - hash from &get_scantron_config()
+ $line - Number of the line being displayed.
+ $questionnum - Question number (may include subquestion)
+ $error - Type of error.
+ @selected - Array of bubbles picked on this line.
- $r->print('
');
+=cut
- # FIXME: This may have to be a bit more clever for
- # multiline questions (different values e.g..).
+sub scantron_bubble_selector {
+ my ($r,$scan_config,$line,$questionnum,$error,@selected)=@_;
+ my $max=$$scan_config{'Qlength'};
- for (my $i=0;$i<$max;$i++) {
- my $value = "$l:$i"; # Relative bubble line #: Bubble in line.
- $r->print("\n".
- '
');
+ $r->print(&Apache::loncommon::end_data_table_row().
+ &Apache::loncommon::end_data_table());
}
=pod
@@ -6795,7 +7077,6 @@ sub scantron_validate_doublebubble {
#get scantron line setup
my %scantron_config=&get_scantron_config($env{'form.scantron_format'});
my ($scanlines,$scan_data)=&scantron_getfile();
-
&scantron_get_maxbubble(); # parse needs the bubble line array.
for (my $i=0;$i<=$scanlines->{'count'};$i++) {
@@ -6822,14 +7103,17 @@ sub scantron_validate_doublebubble {
for what the current value of the problem counter is.
Caches the results to $env{'form.scantron_maxbubble'},
- $env{'form.scantron.bubble_lines.n'} and
- $env{'form.scantron.first_bubble_line.n'}
+ $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 reponse n and number of the first bubble line for response n.
+ 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 items only), for response n.
=cut
-sub scantron_get_maxbubble {
+sub scantron_get_maxbubble {
if (defined($env{'form.scantron_maxbubble'}) &&
$env{'form.scantron_maxbubble'}) {
&restore_bubble_lines();
@@ -6851,13 +7135,23 @@ sub scantron_get_maxbubble {
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();
- &Apache::lonxml::clear_bubble_lines_for_part();
+ # Need to retrieve part IDs and response IDs because essayresponse
+ # 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()}) {
+ my @resp_ids = $resource->responseIds($part);
+ foreach my $id (@resp_ids) {
+ $possible_part_ids{$part.'.'.$id} = 1;
+ }
+ }
+ }
my $result=&Apache::lonnet::ssi($resource->src(),
('symb' => $resource->symb()),
('grade_target' => 'analyze'),
@@ -6867,20 +7161,60 @@ sub scantron_get_maxbubble {
my (undef, $an) =
split(/_HASH_REF__/,$result, 2);
- my %analysis = &Apache::lonnet::str2hash($an);
-
-
+ my @parts;
- foreach my $part_id (@{$analysis{'parts'}}) {
+ my %analysis = &Apache::lonnet::str2hash($an);
+ if (ref($analysis{'parts'}) eq 'ARRAY') {
+ @parts = @{$analysis{'parts'}};
+ }
+ # Add part_ids for any essayresponse items.
+ foreach my $part_id (keys(%possible_part_ids)) {
+ if ($analysis{$part_id.'.type'} eq 'essayresponse') {
+ if (!grep(/^\Q$part_id\E$/,@parts)) {
+ push (@parts,$part_id);
+ }
+ }
+ }
- my $lines = $analysis{"$part_id.bubble_lines"};;
+ foreach my $part_id (@parts) {
+ my $lines = $analysis{"$part_id.bubble_lines"};
# TODO - make this a persistent hash not an array.
+ # optionresponse and matchresponse type items render as
+ # separate sub-questions in exam mode.
+ if (($analysis{$part_id.'.type'} eq 'optionresponse') ||
+ ($analysis{$part_id.'.type'} eq 'matchresponse')) {
+ 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'}});
+ }
+ }
+ 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/,$//;
+ }
- $first_bubble_line{$response_number} = $bubble_line;
- $bubble_lines_per_response{$response_number} = $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;
@@ -6928,7 +7262,25 @@ sub scantron_validate_missingbubbles {
# Probably here's where the error is...
foreach my $missing (@{$$scan_record{'scantron.missingerror'}}) {
- if ($missing > $max_bubble) { next; }
+ my $lastbubble;
+ if ($missing =~ /^(\d+)\.(\d+)$/) {
+ my $question = $1;
+ my $subquestion = $2;
+ if (!defined($first_bubble_line{$question -1})) { next; }
+ my $first = $first_bubble_line{$question-1};
+ my @subans = split(/,/,$subdivided_bubble_lines{$question-1});
+ my $subcount = 1;
+ while ($subcount<$subquestion) {
+ $first += $subans[$subcount-1];
+ $subcount ++;
+ }
+ my $count = $subans[$subquestion-1];
+ $lastbubble = $first + $count;
+ } else {
+ if (!defined($first_bubble_line{$missing - 1})) { next; }
+ $lastbubble = $first_bubble_line{$missing - 1} + $bubble_lines_per_response{$missing - 1};
+ }
+ if ($lastbubble > $max_bubble) { next; }
push(@to_correct,$missing);
}
if (@to_correct) {
@@ -7087,7 +7439,7 @@ sub scantron_upload_scantron_data {
my $domsel=&Apache::loncommon::select_dom_form($env{'request.role.domain'},
'domainid');
my $default_form_data=&defaultFormData(&get_symb($r,1));
- $r->print(<print('
-
-$default_form_data
+
+'.$default_form_data.'
-
$select_link
-
Course ID:
-
Course Name:
-
Domain:
$domsel
-
File to upload:
+
'.$select_link.'
+
'.&mt('Course ID:').'
+
+
'.&mt('Course Name:').'
+
+
'.&mt('Domain:').'
+
'.$domsel.'
+
'.&mt('File to upload:').'
+
-
-
+
+
-UPLOAD
+');
return '';
}
@@ -7129,12 +7485,12 @@ sub scantron_upload_scantron_data_save {
my $doanotherupload=
'
'."\n".
''."\n".
- ''."\n".
+ ''."\n".
'
'."\n";
if (!&Apache::lonnet::allowed('usc',$env{'form.domainid'}) &&
!&Apache::lonnet::allowed('usc',
$env{'form.domainid'}.'_'.$env{'form.courseid'})) {
- $r->print("You are not allowed to upload Scantron data to the requested course. ");
+ $r->print(&mt("You are not allowed to upload Scantron data to the requested course.")." ");
if ($symb) {
$r->print(&show_grading_menu_form($symb));
} else {
@@ -7143,7 +7499,7 @@ sub scantron_upload_scantron_data_save {
return '';
}
my %coursedata=&Apache::lonnet::coursedescription($env{'form.domainid'}.'_'.$env{'form.courseid'});
- $r->print("Doing upload to ".$coursedata{'description'}." ");
+ $r->print(&mt("Doing upload to [_1]",$coursedata{'description'})." ");
my $fname=$env{'form.upfile.filename'};
#FIXME
#copied from lonnet::userfileupload()
@@ -7161,13 +7517,18 @@ sub scantron_upload_scantron_data_save {
my $uploadedfile=$fname;
$fname='scantron_orig_'.$fname;
if (length($env{'form.upfile'}) < 2) {
- $r->print("Error: The file you attempted to upload, ".&HTML::Entities::encode($env{'form.upfile.filename'},'<>&"').", contained no information. Please check that you entered the correct filename.");
+ $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'},'<>&"').""));
} else {
my $result=&Apache::lonnet::finishuserfileupload($env{'form.courseid'},$env{'form.domainid'},'upfile',$fname);
if ($result =~ m|^/uploaded/|) {
- $r->print("Success: Successfully uploaded ".(length($env{'form.upfile'})-1)." bytes of data into location ".$result."");
+ $r->print(&mt("Success: Successfully uploaded [_1] bytes of data into location [_2]",
+ (length($env{'form.upfile'})-1),
+ ''.$result.""));
} else {
- $r->print("Error: An error (".$result.") occurred when attempting to upload the file, ".&HTML::Entities::encode($env{'form.upfile.filename'},'<>&"')."");
+ $r->print(&mt("Error: An error ([_1]) occurred when attempting to upload the file, [_2]",
+ $result,
+ ''.&HTML::Entities::encode($env{'form.upfile.filename'},'<>&"').""));
+
}
}
if ($symb) {
@@ -7211,11 +7572,11 @@ sub scantron_download_scantron_data {
my $cdom=$env{'course.'.$env{'request.course.id'}.'.domain'};
my $file=$env{'form.scantron_selectfile'};
if (! &valid_file($file)) {
- $r->print(<print('
- The requested file name was invalid.
+ '.&mt('The requested file name was invalid.').'
- Original file as uploaded by the scantron office.
+ '.&mt('[_1]Original[_2] file as uploaded by the scantron office.',
+ '','').'
- Corrections, a file of corrected records that were used in grading.
+ '.&mt('[_1]Corrections[_2], a file of corrected records that were used in grading.',
+ '','').'
- Skipped, a file of records that were skipped.
+ '.&mt('[_1]Skipped[_2], a file of records that were skipped.',
+ '','').'