'.
- ''.
- ' Prob. '.
- ' '.($env{'form.vProb'} eq 'no' ? 'Title' : 'Problem Text').'/Grade ';
+ &Apache::loncommon::start_data_table().
+ &Apache::loncommon::start_data_table_header_row().
+ ' Prob. '.
+ ' '.($env{'form.vProb'} eq 'no' ? 'Title' : 'Problem Text').'/Grade '.
+ &Apache::loncommon::end_data_table_header_row();
&Apache::lonxml::clear_problem_counter();
my ($depth,$question,$prob) = (1,1,1);
@@ -4079,7 +4249,9 @@ sub displayPage {
my $parts = $curRes->parts();
my $title = $curRes->compTitle();
my $symbx = $curRes->symb();
- $studentTable.=''.$prob.
+ $studentTable.=
+ &Apache::loncommon::start_data_table_row().
+ ' '.$prob.
(scalar(@{$parts}) == 1 ? '' : ' ('.scalar(@{$parts}).' parts)').' ';
$studentTable.='';
my %form = ('CODE' => $env{'form.CODE'},);
@@ -4153,31 +4325,33 @@ sub displaySubByDates {
my $isCODE=0;
my $isTask = ($symb =~/\.task$/);
if (exists($record->{'resource.CODE'})) { $isCODE=1; }
- my $studentTable=''.
- ''.
- 'Date/Time '.
- ($isCODE?'CODE ':'').
- 'Submission '.
- 'Status ';
+ my $studentTable=&Apache::loncommon::start_data_table().
+ &Apache::loncommon::start_data_table_header_row().
+ ''.&mt('Date/Time').' '.
+ ($isCODE?''.&mt('CODE').' ':'').
+ ''.&mt('Submission').' '.
+ ''.&mt('Status').' '.
+ &Apache::loncommon::end_data_table_header_row();
my ($version);
my %mark;
my %orders;
$mark{'correct_by_student'} = $checkIcon;
if (!exists($$record{'1:timestamp'})) {
- return ' Nothing submitted - no attempts ';
+ return ' '.&mt('Nothing submitted - no attempts').' ';
}
my $interaction;
for ($version=1;$version<=$$record{'version'};$version++) {
- my $timestamp = scalar(localtime($$record{$version.':timestamp'}));
+ my $timestamp =
+ &Apache::lonlocal::locallocaltime($$record{$version.':timestamp'});
if (exists($$record{$version.':resource.0.version'})) {
$interaction = $$record{$version.':resource.0.version'};
}
my $where = ($isTask ? "$version:resource.$interaction"
: "$version:resource");
- #&Apache::lonnet::logthis(" got $where");
- $studentTable.=''.$timestamp.' ';
+ $studentTable.=&Apache::loncommon::start_data_table_row().
+ ''.$timestamp.' ';
if ($isCODE) {
$studentTable.=''.$record->{$version.':resource.CODE'}.' ';
}
@@ -4196,15 +4370,14 @@ sub displaySubByDates {
my ($responseId)= ($isTask ? ($matchKey=~ /^resource\.(.*?)\.\Q$partid\E\.award$/)
: ($matchKey=~ /^resource\.\Q$partid\E\.(.*?)\.submission$/));
- #&Apache::lonnet::logthis("match $matchKey $responseId (".$$record{$version.':'.$matchKey});
- $displaySub[0].='Part: '.$display_part.' ';
- $displaySub[0].='(ID '.
+ $displaySub[0].=''.&mt('Part:').' '.$display_part.' ';
+ $displaySub[0].='('.&mt('ID').' '.
$responseId.') ';
if ($$record{"$where.$partid.tries"} eq '') {
- $displaySub[0].='Trial not counted';
+ $displaySub[0].=&mt('Trial not counted');
} else {
- $displaySub[0].='Trial '.
- $$record{"$where.$partid.tries"};
+ $displaySub[0].=&mt('Trial [_1]',
+ $$record{"$where.$partid.tries"});
}
my $responseType=($isTask ? 'Task'
: $responseType->{$partid}->{$responseId});
@@ -4244,12 +4417,12 @@ sub displaySubByDates {
}
$studentTable.=' '.$displaySub[0].' '.$displaySub[1];
if ($displaySub[2]) {
- $studentTable.='Manually graded by '.$displaySub[2];
+ $studentTable.=&mt('Manually graded by [_1]',$displaySub[2]);
}
- $studentTable.=' ';
-
+ $studentTable.=' '.
+ &Apache::loncommon::end_data_table_row();
}
- $studentTable.='
';
+ $studentTable.=&Apache::loncommon::end_data_table();
return $studentTable;
}
@@ -4286,12 +4459,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().
+ ' Prob. '.
+ ' Title '.
+ ' Previous Score '.
+ ' New Score '.
+ &Apache::loncommon::end_data_table_header_row();
$iterator->next(); # skip the first BEGIN_MAP
my $curRes = $iterator->next(); # for "current resource"
@@ -4304,7 +4479,9 @@ sub updateGradeByPage {
my $parts = $curRes->parts();
my $title = $curRes->compTitle();
my $symbx = $curRes->symb();
- $studentTable.=''.$prob.
+ $studentTable.=
+ &Apache::loncommon::start_data_table_row().
+ ' '.$prob.
(scalar(@{$parts}) == 1 ? '' : ' ('.scalar(@{$parts}).' parts)').' ';
$studentTable.=' '.$title.' ';
@@ -4392,14 +4569,14 @@ sub updateGradeByPage {
$studentTable.=''.$displayPts[0].' '.
''.$displayPts[1].' '.
- ' ';
+ &Apache::loncommon::end_data_table_row();
$prob++;
}
$curRes = $iterator->next();
}
- $studentTable.='
';
+ $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 '.
@@ -4465,10 +4642,7 @@ the homework problem.
=over 4
-=cut
-
-=pod
=item defaultFormData
@@ -4481,12 +4655,12 @@ the homework problem.
sub defaultFormData {
my ($symb)=@_;
- return '
- '."\n".
+ return ' '."\n".
' '."\n".
' '."\n";
}
+
=pod
=item getSequenceDropDown
@@ -4788,11 +4962,10 @@ SCANTRONFORM
SCANTRONFORM
- $r->print(<
-$grading_menu_button
-SCANTRONFORM
-
+ $r->print('');
+ &Apache::lonpickcode::code_list($r,2);
+ $r->print('
');
+ $r->print($grading_menu_button);
return
}
@@ -4957,7 +5130,8 @@ 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');
@@ -4988,28 +5162,58 @@ sub scantron_fixup_scanline {
$$scantron_config{'CODElength'})=$args->{'CODE'};
}
} elsif ($field eq 'answer') {
- my $length=$scantron_config->{'Qlength'};
+ &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;
- if ($args->{'response'} eq 'none') {
- &scan_data($scan_data,
- "$whichline.no_bubble.".$args->{'question'},'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'; }
+ 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 $answer=${off}x($bubbles_per_line*$bubble_count);
+ 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');
} else {
- substr($answer,$args->{'response'},1)=$on;
+ 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= $bubble_number+1;
+ if ($answer == 10) { $answer = '0'; }
+ } else {
+ substr($answer,$bubble_number+$bubble_line*$bubbles_per_line,1)=$on;
+ $final_answer = $answer;
+ }
+ &scan_data($scan_data,
+ "$whichline.no_bubble.".$args->{'question'},undef,'1');
+
+ # Positional notation already has the right final answer length..
+
+ if (($on eq 'letter') || ($on eq 'number')) {
+ for (my $l = 0; $l < $bubble_count; $l++) {
+ if ($l eq $bubble_line) {
+ $final_answer .= $answer;
+ } else {
+ $final_answer .= ' ';
+ }
+ }
+ }
}
- &scan_data($scan_data,
- "$whichline.no_bubble.".$args->{'question'},undef,'1');
+ # $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*$length) = $final_answer;
}
- my $where=$length*($args->{'question'}-1)+$scantron_config->{'Qstart'};
- substr($line,$where-1,$length)=$answer;
}
return $line;
}
@@ -5076,13 +5280,18 @@ sub scan_data {
if just_header was not true these key may also exist
- missingerror - a list of bubbled line numbers that had a blank bubble
- that is considered an error (if the operator had already
- okayed a blank bubble line as really being blank then
- that bubble line number won't appear here.
- doubleerror - a list of bubbled line numbers that had more than one
- bubble filled in and has not been corrected by the
- operator
+ missingerror - a list of bubble ranges that are considered to be answers
+ to a single question that don't have any bubbles filled in.
+ Of the form questionnumber:firstbubblenumber:count.
+ doubleerror - a list of bubble ranges that are considered to be answers
+ to a single question that have more than one bubble filled in.
+ Of the form questionnumber::firstbubblenumber:count
+
+ In the above, count is the number of bubble responses in the
+ input line needed to represent the possible answers to the question.
+ e.g. a radioresponse with 15 choices in an answer sheet with 10 choices
+ per line would have count = 2.
+
maxquest - the number of the last bubble line that was parsed
( starts at 1)
@@ -5097,6 +5306,7 @@ sub scan_data {
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 $data=substr($line,0,$$scantron_config{'Qstart'}-1); # earlier stuff
@@ -5133,68 +5343,169 @@ sub scantron_parse_scanline {
my @alphabet=('A'..'Z');
my $questnum=0;
- while ($questions) {
+ my $ansnum =1; # Multiple 'answer lines'/question.
+
+ chomp($questions); # Get rid of any trailing \n.
+ $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,$$scantron_config{'Qlength'});
- substr($questions,0,$$scantron_config{'Qlength'})='';
- if (length($currentquest) < $$scantron_config{'Qlength'}) { next; }
+ 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 eq '?'
- || $currentquest eq '*') {
+
+ if ($currentquest =~ /\?/
+ || $currentquest =~ /\*/
+ || (&occurence_count($currentquest, "[A-Z]") > 1)) {
push(@{$record{'scantron.doubleerror'}},$questnum);
- $record{"scantron.$questnum.answer"}='';
+ 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)
- || $currentquest eq $$scantron_config{'Qoff'}
- || $currentquest !~ /^[A-Z]$/) {
- $record{"scantron.$questnum.answer"}='';
+ || (&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 {
- $record{"scantron.$questnum.answer"}=$currentquest;
+ 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 eq '?'
- || $currentquest eq '*') {
+ if ($currentquest =~ /\?/
+ || $currentquest =~ /\*/
+ || (&occurence_count($currentquest, '\d') > 1)) {
push(@{$record{'scantron.doubleerror'}},$questnum);
- $record{"scantron.$questnum.answer"}='';
+ 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)
- || $currentquest eq $$scantron_config{'Qoff'}
- || $currentquest !~ /^\d$/) {
- $record{"scantron.$questnum.answer"}='';
+ || (&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;
}
+
} else {
- # wrap zero back to J
- if ($currentquest eq '0') {
- $record{"scantron.$questnum.answer"}=
- $alphabet[9];
- } else {
- $record{"scantron.$questnum.answer"}=
- $alphabet[$currentquest-1];
+ $currentquest = &digits_to_letters($currentquest);
+ for (my $ans =0; $ans < $answers_needed; $ans++) {
+ $record{"scantron.$ansnum.answer"} = substr($currentquest, $ans, 1);
+ $ansnum++;
}
}
} else {
+
+ # 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 @array=split($$scantron_config{'Qon'},$currentquest,-1);
- if (length($array[0]) eq $$scantron_config{'Qlength'}) {
- $record{"scantron.$questnum.answer"}='';
+
+ # If the split only giveas us one element.. the full length of the
+ # answser string, no bubbles are filled in:
+
+ 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.$questnum")) {
push(@{$record{"scantron.missingerror"}},$questnum);
}
- } else {
- $record{"scantron.$questnum.answer"}=
- $alphabet[length($array[0])];
+
+ # If the bubble is not the last position, there will be
+ # 2 elements. If it is the last position, there will be 1 element.
+
+ } elsif (scalar(@array) le 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++;
+ }
}
- if (scalar(@array) gt 2) {
+ # 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=length($ans[0]);shift(@ans);
+ my $i=0;
+ my $increment = 0;
while ($#ans) {
- $i+=length($ans[0])+1;
- $record{"scantron.$questnum.answer"}.=$alphabet[$i];
+ $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;
}
}
}
@@ -5551,6 +5862,16 @@ sub scantron_form_start {
SCANTRONFORM
+
+ my $line = 0;
+ while (defined($env{"form.scantron.bubblelines.$line"})) {
+ my $chunk =
+ ' '."\n";
+ $chunk .=
+ ' '."\n";
+ $result .= $chunk;
+ $line++;
+ }
return $result;
}
@@ -5609,6 +5930,7 @@ sub scantron_validate_file {
}
my $currentphase=$env{'form.validatepass'};
+
my $stop=0;
while (!$stop && $currentphase < scalar(@validate_phases)) {
$r->print(" Validating ".$validate_phases[$currentphase]."
");
@@ -6032,6 +6354,8 @@ sub scantron_validate_ID {
#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_lines.. array.
my %found=('ids'=>{},'usernames'=>{});
for (my $i=0;$i<=$scanlines->{'count'};$i++) {
@@ -6117,7 +6441,7 @@ 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, probaly need
+#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
@@ -6216,9 +6540,10 @@ ENDSCRIPT
$r->print($message);
$r->print("Please indicate which bubble should be used for grading
");
foreach my $question (@{$arg}) {
- my $selected=$$scan_record{"scantron.$question.answer"};
+ my $selected = &get_response_bubbles($scan_record, $question);
+ my @select_array = split(/:/,$selected);
&scantron_bubble_selector($r,$scan_config,$question,
- split('',$selected));
+ @select_array);
}
} elsif ($error eq 'missingbubble') {
$r->print("There have been no bubbles scanned for some question(s)
\n");
@@ -6228,8 +6553,9 @@ ENDSCRIPT
$r->print(' ');
foreach my $question (@{$arg}) {
- my $selected=$$scan_record{"scantron.$question.answer"};
- &scantron_bubble_selector($r,$scan_config,$question);
+ 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);
}
} else {
$r->print("\n");
@@ -6249,35 +6575,35 @@ ENDSCRIPT
$r - Apache request object
$scan_config - hash from &get_scantron_config()
$quest - number of the bubble line to make a corrector for
- $selected - array of letters of previously selected bubbles
- $lines - if present, number of bubble lines to show
+ @lines - array of answer lines.
=cut
sub scantron_bubble_selector {
- my ($r,$scan_config,$quest,@selected, $lines)=@_;
+ my ($r,$scan_config,$quest,@lines)=@_;
my $max=$$scan_config{'Qlength'};
+
my $scmode=$$scan_config{'Qon'};
+
+ my $bubble_length = scalar(@lines);
+
+
if ($scmode eq 'number' || $scmode eq 'letter') { $max=10; }
+ my $response = $quest-1;
+ my $lines = $bubble_lines_per_response{$response};
- if (!defined($lines)) {
- $lines = 1;
- }
my $total_lines = $lines*2;
my @alphabet=('A'..'Z');
+
$r->print("$quest ");
for (my $l = 0; $l < $lines; $l++) {
if ($l != 0) {
$r->print('');
}
-
- # FIXME: This loop probably has to be considerably more clever for
- # multiline bubbles: User can multibubble by having bubbles in
- # several lines. User can skip lines legitimately etc. etc.
-
+ my @selected = split(//,$lines[$l]);
for (my $i=0;$i<$max;$i++) {
$r->print("\n".'');
if ($selected[0] eq $alphabet[$i]) {
@@ -6304,9 +6630,10 @@ sub scantron_bubble_selector {
# multiline questions (different values e.g..).
for (my $i=0;$i<$max;$i++) {
+ my $value = "$l:$i"; # Relative bubble line #: Bubble in line.
$r->print("\n".
' '.$alphabet[$i]." ");
+ $quest.'" value="'.$value.'" />'.$alphabet[$i]."");
}
$r->print(' ');
@@ -6438,6 +6765,8 @@ sub scantron_validate_CODE {
my %allcodes=&get_codes();
+ &scantron_get_maxbubble(); # parse needs the lines per response array.
+
my ($scanlines,$scan_data)=&scantron_getfile();
for (my $i=0;$i<=$scanlines->{'count'};$i++) {
my $line=&scantron_get_line($scanlines,$scan_data,$i);
@@ -6490,6 +6819,9 @@ 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++) {
my $line=&scantron_get_line($scanlines,$scan_data,$i);
if ($line=~/^[\s\cz]*$/) { next; }
@@ -6513,21 +6845,25 @@ sub scantron_validate_doublebubble {
resource and then checking &Apache::lonxml::get_problem_counter()
for what the current value of the problem counter is.
- Caches the result to $env{'form.scantron_maxbubble'}
+ Caches the results to $env{'form.scantron_maxbubble'},
+ $env{'form.scantron.bubble_lines.n'} and
+ $env{'form.scantron.first_bubble_line.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.
=cut
sub scantron_get_maxbubble {
-
if (defined($env{'form.scantron_maxbubble'}) &&
$env{'form.scantron_maxbubble'}) {
+ &restore_bubble_lines();
return $env{'form.scantron_maxbubble'};
}
- my $navmap=Apache::lonnavmaps::navmap->new();
- my (undef,undef,$sequence)=
+ my (undef, undef, $sequence) =
&Apache::lonnet::decode_symb($env{'form.selectpage'});
+ my $navmap=Apache::lonnavmaps::navmap->new();
my $map=$navmap->getResourceByUrl($sequence);
my @resources=$navmap->retrieveResources($map,\&scantron_filter,1,0);
@@ -6538,9 +6874,14 @@ sub scantron_get_maxbubble {
my $cid = $env{'request.course.id'};
my $total_lines = 0;
%bubble_lines_per_response = ();
+ %first_bubble_line = ();
+
+ my $response_number = 0;
+ my $bubble_line = 0;
foreach my $resource (@resources) {
my $symb = $resource->symb();
+ &Apache::lonxml::clear_bubble_lines_for_part();
my $result=&Apache::lonnet::ssi($resource->src(),
('symb' => $resource->symb()),
('grade_target' => 'analyze'),
@@ -6555,16 +6896,25 @@ sub scantron_get_maxbubble {
foreach my $part_id (@{$analysis{'parts'}}) {
- my $bubble_lines = $analysis{"$part_id.bubble_lines"}[0];
- if (!$bubble_lines) {
- $bubble_lines = 1;
- }
- $bubble_lines_per_response{"$symb.$part_id"} = $bubble_lines;
- $total_lines = $total_lines + $bubble_lines;
+
+
+ my $lines = $analysis{"$part_id.bubble_lines"};;
+
+ # TODO - make this a persistent hash not an array.
+
+
+ $first_bubble_line{$response_number} = $bubble_line;
+ $bubble_lines_per_response{$response_number} = $lines;
+ $response_number++;
+
+ $bubble_line += $lines;
+ $total_lines += $lines;
}
}
&Apache::lonnet::delenv('scantron\.');
+
+ &save_bubble_lines();
$env{'form.scantron_maxbubble'} =
$total_lines;
return $env{'form.scantron_maxbubble'};
@@ -6575,7 +6925,8 @@ sub scantron_get_maxbubble {
=item scantron_validate_missingbubbles
Validates all scanlines in the selected file to not have any
- bubble lines with missing bubbles that haven't been verified as missing.
+ answers that don't have bubbles that have not been verified
+ to be bubble free.
=cut
@@ -6597,6 +6948,9 @@ sub scantron_validate_missingbubbles {
$scan_data);
if (!defined($$scan_record{'scantron.missingerror'})) { next; }
my @to_correct;
+
+ # Probably here's where the error is...
+
foreach my $missing (@{$$scan_record{'scantron.missingerror'}}) {
if ($missing > $max_bubble) { next; }
push(@to_correct,$missing);
@@ -6669,6 +7023,9 @@ SCANTRONFORM
my $start=&Time::HiRes::time();
my $i=-1;
my ($uname,$udom,$started);
+
+ &scantron_get_maxbubble(); # Need the bubble lines array to parse.
+
while ($i<$scanlines->{'count'}) {
($uname,$udom)=('','');
$i++;
@@ -6719,8 +7076,6 @@ SCANTRONFORM
}
my $result=&Apache::lonnet::ssi($resource->src(),%form);
if ($result ne '') {
- &Apache::lonnet::logthis("scantron grading error -> $result");
- &Apache::lonnet::logthis("scantron grading error info name $uname domain $udom course $env{'request.course.id'} url ".$resource->src());
}
if (&Apache::loncommon::connection_aborted($r)) { last; }
}
@@ -6928,7 +7283,7 @@ sub show_grading_menu_form {
' '."\n".
' '."\n".
' '."\n".
- ' '."\n".
+ ' '."\n".
''."\n";
return $result;
}
@@ -6945,8 +7300,127 @@ sub savedState {
return \%savedState;
}
-#--- Displays the main menu page -------
-sub gradingmenu {
+sub grading_menu {
+ my ($request) = @_;
+ my ($symb)=&get_symb($request);
+ if (!$symb) {return '';}
+ my $probTitle = &Apache::lonnet::gettitle($symb);
+ my ($table,undef,$hdgrade) = &showResourceInfo($symb,$probTitle);
+
+ $request->print($table);
+ my %fields = ('symb'=>&Apache::lonenc::check_encrypt($symb),
+ 'handgrade'=>$hdgrade,
+ 'probTitle'=>$probTitle,
+ 'command'=>'submit_options',
+ '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.'),
+ });
+ $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.')});
+ $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.')});
+ $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('')});
+ #
+ # Create the menu
+ my $Str;
+ # $Str .= ''.&mt('Please select a grading task').' ';
+ $Str .= '\n";
+ $request->print(<
+ function checkChoice(formname,val,cmdx) {
+ if (val <= 2) {
+ var cmd = radioSelection(formname.radioChoice);
+ var cmdsave = cmd;
+ } else {
+ cmd = cmdx;
+ cmdsave = 'submission';
+ }
+ formname.command.value = cmd;
+ if (val < 5) formname.submit();
+ if (val == 5) {
+ if (!checkReceiptNo(formname,'notOK')) {
+ return false;
+ } else {
+ formname.submit();
+ }
+ }
+ }
+
+ function checkReceiptNo(formname,nospace) {
+ var receiptNo = formname.receipt.value;
+ var checkOpt = false;
+ 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.");
+ formname.receipt.value = "";
+ formname.receipt.focus();
+ return false;
+ }
+ return true;
+ }
+
+GRADINGMENUJS
+ &commonJSfunctions($request);
+ return $Str;
+}
+
+
+#--- Displays the submissions first page -------
+sub submit_options {
my ($request) = @_;
my ($symb)=&get_symb($request);
if (!$symb) {return '';}
@@ -6989,9 +7463,8 @@ sub gradingmenu {
GRADINGMENUJS
&commonJSfunctions($request);
- my $result=' Manual Grading/View Submission ';
my ($table,undef,$hdgrade) = &showResourceInfo($symb,$probTitle);
- $result.=$table;
+ my $result;
my (undef,$sections) = &getclasslist('all','0');
my $savedState = &savedState();
my $saveCmd = ($$savedState{'saveCmd'} eq '' ? 'submission' : $$savedState{'saveCmd'});
@@ -7008,95 +7481,104 @@ GRADINGMENUJS
' '."\n".
' '."\n";
- $result.=''."\n".
- ''."\n".
- ' Select a Grading/Viewing Option '."\n".
- ''."\n";
-
- $result.=''."\n";
-
- $result.=' ';
-
- $result.=''."\n".
- '
'."\n".
- '
'."\n";
+ $result.='
+
+
+
+
+
+ '.&Apache::lonstatistics::GroupSelect('group','multiple',5).'
+
+
+
+
+
+ '.&Apache::lonhtmlcommon::StatusOptions($saveStatus,undef,5,undef,'mult').'
+
+
+
+
+
+
+ '.&mt('with submissions').'
+ '.&mt('in grading queue').'
+ '.&mt('with ungraded submissions').'
+ '.&mt('with incorrect submissions').'
+ '.&mt('with any status').'
+
+
+
+
+
+
+
+
+ '.&mt('Grade Complete Folder for One Student').'
+
+
+
+
+ ';
return $result;
}
@@ -7270,9 +7752,9 @@ function sanitycheck() {
$type: $selectform
-$attendance:
-$personnel:
-$specific:
+ $attendance
+ $personnel
+ $specific
$pcorrect:
@@ -7375,6 +7857,8 @@ ENDHEADER
}
$result.=' '.&mt('Found [_1] question(s)',$number).' '.
' '.
+ &mt('Awarding [_1] percent for corrion(s)',$number).' '.
+ ' '.
&mt('Awarding [_1] percent for correct and [_2] percent for incorrect responses',
$env{'form.pcorrect'},$env{'form.pincorrect'}).
' ';
@@ -7605,7 +8089,6 @@ ENDHEADER
sub handler {
my $request=$_[0];
-
&reset_caches();
if ($env{'browser.mathml'}) {
&Apache::loncommon::content_type($request,'text/xml');
@@ -7618,9 +8101,12 @@ sub handler {
my $symb=&get_symb($request,1);
my @commands=&Apache::loncommon::get_env_multiple('form.command');
my $command=$commands[0];
+
if ($#commands > 0) {
&Apache::lonnet::logthis("grades got multiple commands ".join(':',@commands));
}
+
+
$request->print(&Apache::loncommon::start_page('Grading'));
if ($symb eq '' && $command eq '') {
if ($env{'user.adv'}) {
@@ -7661,7 +8147,9 @@ sub handler {
} elsif ($command eq 'processGroup' && $perm{'vgr'}) {
&processGroup($request);
} elsif ($command eq 'gradingmenu' && $perm{'vgr'}) {
- $request->print(&gradingmenu($request));
+ $request->print(&grading_menu($request));
+ } elsif ($command eq 'submit_options' && $perm{'vgr'}) {
+ $request->print(&submit_options($request));
} elsif ($command eq 'viewgrades' && $perm{'vgr'}) {
$request->print(&viewgrades($request));
} elsif ($command eq 'handgrade' && $perm{'mgr'}) {