--- loncom/homework/grades.pm 2006/03/28 18:07:24 1.344 +++ loncom/homework/grades.pm 2006/10/23 22:32:09 1.381 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # The LON-CAPA Grading handler # -# $Id: grades.pm,v 1.344 2006/03/28 18:07:24 albertel Exp $ +# $Id: grades.pm,v 1.381 2006/10/23 22:32:09 albertel Exp $ # # Copyright Michigan State University Board of Trustees # @@ -36,10 +36,13 @@ use Apache::lonhtmlcommon; use Apache::lonnavmaps; use Apache::lonhomework; use Apache::loncoursedata; -use Apache::lonmsg qw(:user_normal_msg); +use Apache::lonmsg(); use Apache::Constants qw(:common); use Apache::lonlocal; use String::Similarity; +use lib '/home/httpd/lib/perl'; +use LONCAPA; + use POSIX qw(floor); my %oldessays=(); @@ -109,36 +112,34 @@ sub nameUserString { #--- Indicate if a response type is coded handgraded or not. --- sub response_type { my ($symb) = shift; - my (undef,undef,$url) = &Apache::lonnet::decode_symb($symb); - my $allkeys = &Apache::lonnet::metadata($url,'keys'); - my %vPart; - foreach my $partid (&Apache::loncommon::get_env_multiple('form.vPart')) { - $vPart{$partid}=1; - } - my %seen = (); - my (@partlist,%handgrade,%responseType); - foreach (split(/,/,&Apache::lonnet::metadata($url,'packages'))) { - if (/^\w+response_.*/ || /^Task_/) { - my ($responsetype,$part) = split(/_/,$_,2); - my ($partid,$respid) = split(/_/,$part); - if ($responsetype eq 'Task') { $respid='0'; } - if (&Apache::loncommon::check_if_partid_hidden($partid,$symb)) { - next; - } - if (%vPart && !exists($vPart{$partid})) { - next; - } - $responsetype =~ s/response$//; # make it compatible w/ navmaps - should move to that!! - my ($value) = &Apache::lonnet::EXT('resource.'.$part.'.handgrade',$symb); - $handgrade{$part} = ($value eq 'yes' ? 'yes' : 'no'); - if (!exists($responseType{$partid})) { $responseType{$partid}={}; } - $responseType{$partid}->{$respid}=$responsetype; - next if ($seen{$partid} > 0); - $seen{$partid}++; - push @partlist,$partid; - } - } - return (\@partlist,\%handgrade,\%responseType); + + my $navmap = Apache::lonnavmaps::navmap->new(); + my $res = $navmap->getBySymb($symb); + my $partlist = $res->parts(); + my (%response_types,%handgrade); + foreach my $part (@{ $partlist }) { + my @types = $res->responseType($part); + my @ids = $res->responseIds($part); + for (my $i=0; $i < scalar(@ids); $i++) { + $response_types{$part}{$ids[$i]} = $types[$i]; + $handgrade{$part.'_'.$ids[$i]} = + &Apache::lonnet::EXT('resource.'.$part.'_'.$ids[$i]. + '.handgrade',$symb); + } + } + return ($partlist,\%handgrade,\%response_types); +} + +sub flatten_responseType { + my ($responseType) = @_; + my @part_response_id = + map { + my $part = $_; + map { + [$part,$_] + } sort(keys(%{ $responseType->{$part} })); + } sort(keys(%$responseType)); + return @part_response_id; } sub get_display_part { @@ -165,25 +166,26 @@ sub showResourceInfo { my %resptype = (); my $hdgrade='no'; my %partsseen; - for my $part_resID (sort keys(%$handgrade)) { - my $handgrade=$$handgrade{$part_resID}; - my ($partID,$resID) = split(/_/,$part_resID); - my $responsetype = $responseType->{$partID}->{$resID}; - $hdgrade = $handgrade if ($handgrade eq 'yes'); - $result.='<tr>'; - if ($checkboxes) { - if (exists($partsseen{$partID})) { - $result.="<td> </td>"; - } else { - $result.="<td><input type='checkbox' name='vPart' value='$partID' checked='on' /></td>"; + foreach my $partID (sort keys(%$responseType)) { + foreach my $resID (sort keys(%{ $responseType->{$partID} })) { + my $handgrade=$$handgrade{$partID.'_'.$resID}; + my $responsetype = $responseType->{$partID}->{$resID}; + $hdgrade = $handgrade if ($handgrade eq 'yes'); + $result.='<tr>'; + if ($checkboxes) { + if (exists($partsseen{$partID})) { + $result.="<td> </td>"; + } else { + $result.="<td><input type='checkbox' name='vPart' value='$partID' checked='on' /></td>"; + } + $partsseen{$partID}=1; } - $partsseen{$partID}=1; - } - my $display_part=&get_display_part($partID,$symb); - $result.='<td><b>Part: </b>'.$display_part.' <font color="#999999">'. - $resID.'</font></td>'. - '<td><b>Type: </b>'.$responsetype.'</td></tr>'; + my $display_part=&get_display_part($partID,$symb); + $result.='<td><b>Part: </b>'.$display_part.' <font color="#999999">'. + $resID.'</font></td>'. + '<td><b>Type: </b>'.$responsetype.'</td></tr>'; # '<td><b>Handgrade: </b>'.$handgrade.'</td></tr>'; + } } $result.='</table>'."\n"; return $result,$responseType,$hdgrade,$partlist,$handgrade; @@ -586,7 +588,7 @@ sub verifyreceipt { my $receipt = &Apache::lonnet::recprefix($courseid).'-'. $env{'form.receipt'}; $receipt =~ s/[^\-\d]//g; - my $symb = &Apache::lonnet::symbread(); + my ($symb) = &get_symb($request); my $title.='<h3><font color="#339933">Verifying Submission Receipt '. $receipt.'</h3></font>'."\n". @@ -722,7 +724,14 @@ LISTJAVASCRIPT $gradeTable.='<label><input type="radio" name="lastSub" value="lastonly" '.$checklastsub.' /> last submission only </label>'."\n". '<label><input type="radio" name="lastSub" value="last" /> last submission & parts info </label>'."\n". '<label><input type="radio" name="lastSub" value="datesub" /> by dates and submissions </label>'."\n". - '<label><input type="radio" name="lastSub" value="all" /> all details</label>'."\n". + '<label><input type="radio" name="lastSub" value="all" /> all details</label><br />'."\n". + ' <b>Grading Increments:</b> <select name="increment">'. + '<option value="1">Whole Points</option>'. + '<option value=".5">Half Points</option>'. + '<option value=".25">Quarter Points</option>'. + '<option value=".1">Tenths of a Point</option>'. + '</select>'. + '<input type="hidden" name="section" value="'.$getsec.'" />'."\n". '<input type="hidden" name="submitonly" value="'.$submitonly.'" />'."\n". '<input type="hidden" name="handgrade" value="'.$env{'form.handgrade'}.'" /><br />'."\n". @@ -1135,6 +1144,81 @@ sub sub_page_kw_js { my $request = shift; my $iconpath = $request->dir_config('lonIconsURL'); &commonJSfunctions($request); + + my $inner_js_msg_central=<<INNERJS; + <script text="text/javascript"> + function checkInput() { + opener.document.SCORE.msgsub.value = opener.checkEntities(document.msgcenter.msgsub.value); + var nmsg = opener.document.SCORE.savemsgN.value; + var usrctr = document.msgcenter.usrctr.value; + var newval = opener.document.SCORE["newmsg"+usrctr]; + newval.value = opener.checkEntities(document.msgcenter.newmsg.value); + + var msgchk = ""; + if (document.msgcenter.subchk.checked) { + msgchk = "msgsub,"; + } + var includemsg = 0; + for (var i=1; i<=nmsg; i++) { + var opnmsg = opener.document.SCORE["savemsg"+i]; + var frmmsg = document.msgcenter["msg"+i]; + opnmsg.value = opener.checkEntities(frmmsg.value); + var showflg = opener.document.SCORE["shownOnce"+i]; + showflg.value = "1"; + var chkbox = document.msgcenter["msgn"+i]; + if (chkbox.checked) { + msgchk += "savemsg"+i+","; + includemsg = 1; + } + } + if (document.msgcenter.newmsgchk.checked) { + msgchk += "newmsg"+usrctr; + includemsg = 1; + } + imgformname = opener.document.SCORE["mailicon"+usrctr]; + imgformname.src = "$iconpath/"+((includemsg) ? "mailto.gif" : "mailbkgrd.gif"); + var includemsg = opener.document.SCORE["includemsg"+usrctr]; + includemsg.value = msgchk; + + self.close() + + } + </script> +INNERJS + + my $inner_js_highlight_central=<<INNERJS; + <script type="text/javascript"> + function updateChoice(flag) { + opener.document.SCORE.kwclr.value = opener.radioSelection(document.hlCenter.kwdclr); + opener.document.SCORE.kwsize.value = opener.radioSelection(document.hlCenter.kwdsize); + opener.document.SCORE.kwstyle.value = opener.radioSelection(document.hlCenter.kwdstyle); + opener.document.SCORE.refresh.value = "on"; + if (opener.document.SCORE.keywords.value!=""){ + opener.document.SCORE.submit(); + } + self.close() + } +</script> +INNERJS + + my $start_page_msg_central = + &Apache::loncommon::start_page('Message Central',$inner_js_msg_central, + {'js_ready' => 1, + 'only_body' => 1, + 'bgcolor' =>'#FFFFFF',}); + my $end_page_msg_central = + &Apache::loncommon::end_page({'js_ready' => 1}); + + + my $start_page_highlight_central = + &Apache::loncommon::start_page('Highlight Central', + $inner_js_highlight_central, + {'js_ready' => 1, + 'only_body' => 1, + 'bgcolor' =>'#FFFFFF',}); + my $end_page_highlight_central = + &Apache::loncommon::end_page({'js_ready' => 1}); + my $docopen=&Apache::lonhtmlcommon::javascript_docopen(); $docopen=~s/^document\.//; $request->print(<<SUBJAVASCRIPT); @@ -1250,51 +1334,7 @@ sub sub_page_kw_js { pWin.focus(); pDoc = pWin.document; pDoc.$docopen; - pDoc.write("<html><head>"); - pDoc.write("<title>Message Central</title>"); - - pDoc.write("<script language=javascript>"); - pDoc.write("function checkInput() {"); - pDoc.write(" opener.document.SCORE.msgsub.value = opener.checkEntities(document.msgcenter.msgsub.value);"); - pDoc.write(" var nmsg = opener.document.SCORE.savemsgN.value;"); - pDoc.write(" var usrctr = document.msgcenter.usrctr.value;"); - pDoc.write(" var newval = opener.document.SCORE[\\"newmsg\\"+usrctr];"); - pDoc.write(" newval.value = opener.checkEntities(document.msgcenter.newmsg.value);"); - - pDoc.write(" var msgchk = \\"\\";"); - pDoc.write(" if (document.msgcenter.subchk.checked) {"); - pDoc.write(" msgchk = \\"msgsub,\\";"); - pDoc.write(" }"); - pDoc.write(" var includemsg = 0;"); - pDoc.write(" for (var i=1; i<=nmsg; i++) {"); - pDoc.write(" var opnmsg = opener.document.SCORE[\\"savemsg\\"+i];"); - pDoc.write(" var frmmsg = document.msgcenter[\\"msg\\"+i];"); - pDoc.write(" opnmsg.value = opener.checkEntities(frmmsg.value);"); - pDoc.write(" var showflg = opener.document.SCORE[\\"shownOnce\\"+i];"); - pDoc.write(" showflg.value = \\"1\\";"); - pDoc.write(" var chkbox = document.msgcenter[\\"msgn\\"+i];"); - pDoc.write(" if (chkbox.checked) {"); - pDoc.write(" msgchk += \\"savemsg\\"+i+\\",\\";"); - pDoc.write(" includemsg = 1;"); - pDoc.write(" }"); - pDoc.write(" }"); - pDoc.write(" if (document.msgcenter.newmsgchk.checked) {"); - pDoc.write(" msgchk += \\"newmsg\\"+usrctr;"); - pDoc.write(" includemsg = 1;"); - pDoc.write(" }"); - pDoc.write(" imgformname = opener.document.SCORE[\\"mailicon\\"+usrctr];"); - pDoc.write(" imgformname.src = \\"$iconpath/\\"+((includemsg) ? \\"mailto.gif\\" : \\"mailbkgrd.gif\\");"); - pDoc.write(" var includemsg = opener.document.SCORE[\\"includemsg\\"+usrctr];"); - pDoc.write(" includemsg.value = msgchk;"); - - pDoc.write(" self.close()"); - - pDoc.write("}"); - - pDoc.write("<"); - pDoc.write("/script>"); - - pDoc.write("</head><body bgcolor=white>"); + pDoc.write('$start_page_msg_central'); pDoc.write("<form action=\\"inactive\\" name=\\"msgcenter\\">"); pDoc.write("<input value=\\""+usrctr+"\\" name=\\"usrctr\\" type=\\"hidden\\">"); @@ -1335,7 +1375,7 @@ sub sub_page_kw_js { pDoc.write("<input type=\\"button\\" value=\\"Save\\" onClick=\\"javascript:checkInput()\\"> "); pDoc.write("<input type=\\"button\\" value=\\"Cancel\\" onClick=\\"self.close()\\"><br /><br />"); pDoc.write("</form>"); - pDoc.write("</body></html>"); + pDoc.write('$end_page_msg_central'); pDoc.close(); } @@ -1381,26 +1421,7 @@ sub sub_page_kw_js { hwdWin.focus(); var hDoc = hwdWin.document; hDoc.$docopen; - hDoc.write("<html><head>"); - hDoc.write("<title>Highlight Central</title>"); - - hDoc.write("<script language=javascript>"); - hDoc.write("function updateChoice(flag) {"); - hDoc.write(" opener.document.SCORE.kwclr.value = opener.radioSelection(document.hlCenter.kwdclr);"); - hDoc.write(" opener.document.SCORE.kwsize.value = opener.radioSelection(document.hlCenter.kwdsize);"); - hDoc.write(" opener.document.SCORE.kwstyle.value = opener.radioSelection(document.hlCenter.kwdstyle);"); - hDoc.write(" opener.document.SCORE.refresh.value = \\"on\\";"); - hDoc.write(" if (opener.document.SCORE.keywords.value!=\\"\\"){"); - hDoc.write(" opener.document.SCORE.submit();"); - hDoc.write(" }"); - hDoc.write(" self.close()"); - hDoc.write("}"); - - hDoc.write("<"); - hDoc.write("/script>"); - - hDoc.write("</head><body bgcolor=white>"); - + hDoc.write('$start_page_highlight_central'); hDoc.write("<form action=\\"inactive\\" name=\\"hlCenter\\">"); hDoc.write("<font color=\\"green\\" size=+1> Keyword Highlight Options</font><br /><br />"); @@ -1428,7 +1449,7 @@ sub sub_page_kw_js { hDoc.write("<input type=\\"button\\" value=\\"Save\\" onClick=\\"javascript:updateChoice(1)\\"> "); hDoc.write("<input type=\\"button\\" value=\\"Cancel\\" onClick=\\"self.close()\\"><br /><br />"); hDoc.write("</form>"); - hDoc.write("</body></html>"); + hDoc.write('$end_page_highlight_central'); hDoc.close(); } @@ -1436,10 +1457,20 @@ sub sub_page_kw_js { SUBJAVASCRIPT } +sub get_increment { + my $increment = $env{'form.increment'}; + if ($increment != 1 && $increment != .5 && $increment != .25 && + $increment != .1) { + $increment = 1; + } + return $increment; +} + #--- displays the grading box, used in essay type problem and grading by page/sequence sub gradeBox { my ($request,$symb,$uname,$udom,$counter,$partid,$record) = @_; - my $checkIcon = '<img src="'.$request->dir_config('lonIconsURL'). + my $checkIcon = '<img alt="'.&mt('Check Mark'). + '" src="'.$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 ? '(problem weight)' : @@ -1458,13 +1489,16 @@ sub gradeBox { $result.='<table border="0"><tr><td>'. '<b>Part: </b>'.$display_part.' <b>Points: </b></td><td>'."\n"; my $ctr = 0; + my $thisweight = 0; + my $increment = &get_increment(); $result.='<table border="0"><tr>'."\n"; # display radio buttons in a nice table 10 across - while ($ctr<=$wgt) { - $result.= '<td><nobr><label><input type="radio" name="RADVAL'.$counter.'_'.$partid.'" '. + while ($thisweight<=$wgt) { + $result.= '<td><span style="white-space: nowrap;"><label><input type="radio" name="RADVAL'.$counter.'_'.$partid.'" '. 'onclick="javascript:writeBox(this.form,\''.$counter.'_'.$partid.'\','. - $ctr.')" value="'.$ctr.'" '. - ($score eq $ctr ? 'checked':'').' /> '.$ctr."</label></nobr></td>\n"; + $thisweight.')" value="'.$thisweight.'" '. + ($score eq $thisweight ? 'checked':'').' /> '.$thisweight."</label></span></td>\n"; $result.=(($ctr+1)%10 == 0 ? '</tr><tr>' : ''); + $thisweight += $increment; $ctr++; } $result.='</tr></table>'; @@ -1479,14 +1513,14 @@ sub gradeBox { $result.='<select name="GD_SEL'.$counter.'_'.$partid.'" '. 'onChange="javascript:clearRadBox(this.form,\''.$counter.'_'.$partid.'\')" >'."\n"; if ($$record{'resource.'.$partid.'.solved'} eq 'excused') { - $result.='<option> </option>'. + $result.='<option> </option>'. '<option selected="on">excused</option>'; } else { - $result.='<option selected="on"> </option>'. + $result.='<option selected="on"> </option>'. '<option>excused</option>'; } $result.='<option>reset status</option></select>'."\n"; - $result.="  \n"; + $result.=" \n"; $result.='<input type="hidden" name="stores'.$counter.'_'.$partid.'" value="" />'."\n". '<input type="hidden" name="oldpts'.$counter.'_'.$partid.'" value="'.$score.'" />'."\n". '<input type="hidden" name="solved'.$counter.'_'.$partid.'" value="'. @@ -1504,10 +1538,11 @@ sub handback_box { my ($symb,$uname,$udom,$counter,$partid,$record) = @_; my ($partlist,$handgrade,$responseType) = &response_type($symb); my (@respids); - foreach my $part_resp (sort(keys(%$handgrade))) { - my ($part,$resp) = split(/_/,$part_resp); + my @part_response_id = &flatten_responseType($responseType); + foreach my $part_response_id (@part_response_id) { + my ($part,$resp) = @{ $part_response_id }; if ($part eq $partid) { - push @respids,$resp; + push(@respids,$resp); } } my $result; @@ -1517,12 +1552,18 @@ sub handback_box { next if (!@$files); my $file_counter = 1; foreach my $file (@$files) { - my ($file_disp) = ($file =~ m|.+/(.+)$|); - $result.=&mt('Return commented version of [_1] to student.', - '<span class="filename">'.$file_disp.'</span>'); - $result.='<input type="file" name="'.$prefix.'returndoc'.$file_counter.'" />'."\n"; - $result.='<input type="hidden" name="'.$prefix.'origdoc'.$file_counter.'" value="'.$file.'" /><br />'; - $file_counter++; + if ($file =~ /\/portfolio\//) { + my ($file_path, $file_disp) = ($file =~ m|(.+/)(.+)$|); + my ($name,$version,$ext) = &file_name_version_ext($file_disp); + $file_disp = "$name.$ext"; + $file = $file_path.$file_disp; + $result.=&mt('Return commented version of [_1] to student.', + '<span class="LC_filename">'.$file_disp.'</span>'); + $result.='<input type="file" name="'.$prefix.'returndoc'.$file_counter.'" />'."\n"; + $result.='<input type="hidden" name="'.$prefix.'origdoc'.$file_counter.'" value="'.$file.'" /><br />'; + $result.='(File will be uploaded when you click on Save & Next below.)<br />'; + $file_counter++; + } } } return $result; @@ -1539,7 +1580,7 @@ sub show_problem { if ($removeform) { $rendered=~s|<form(.*?)>||g; $rendered=~s|</form>||g; - $rendered=~s|name="submit"|name="would_have_been_submit"|g; + $rendered=~s|(<input[^>]*name\s*=\s*"?)(\w+)("?)|$1would_have_been_$2$3|g; } my $companswer; if ($mode eq 'both' or $mode eq 'answer') { @@ -1600,7 +1641,8 @@ sub submission { if (!$env{'form.vProb'}) { $env{'form.vProb'} = 'yes'; } if (!$env{'form.vAns'}) { $env{'form.vAns'} = 'yes'; } my $last = ($env{'form.lastSub'} eq 'last' ? 'last' : ''); - my $checkIcon = '<img src="'.$request->dir_config('lonIconsURL'). + my $checkIcon = '<img alt="'.&mt('Check Mark'). + '" src="'.$request->dir_config('lonIconsURL'). '/check.gif" height="16" border="0" />'; # header info @@ -1713,7 +1755,7 @@ KEYWORDS # my (undef,undef,$essayurl) = &Apache::lonnet::decode_symb($symb); my ($adom,$aname,$apath)=($essayurl=~/^(\w+)\/(\w+)\/(.*)$/); - $apath=&Apache::lonnet::escape($apath); + $apath=&escape($apath); $apath=~s/\W/\_/gs; %oldessays=&Apache::lonnet::dump('nohist_essay_'.$apath,$adom,$aname); } @@ -1818,8 +1860,9 @@ KEYWORDS $lastsubonly.='<tr><td bgcolor="#ffffe6">'.$$string[0]; } else { my %seenparts; - for my $part (sort keys(%$handgrade)) { - my ($partid,$respid) = split(/_/,$part); + my @part_response_id = &flatten_responseType($responseType); + foreach my $part (@part_response_id) { + my ($partid,$respid) = @{ $part }; my $display_part=&get_display_part($partid,$symb); if ($env{"form.$uname:$udom:$partid:submitted_by"}) { if (exists($seenparts{$partid})) { next; } @@ -1843,7 +1886,7 @@ KEYWORDS } foreach (@$string) { my ($partid,$respid) = /^resource\.([^\.]*)\.([^\.]*)\.submission/; - if ($part ne ($partid.'_'.$respid)) { next; } + if (join('_',@{$part}) ne ($partid.'_'.$respid)) { next; } my ($ressub,$subval) = split(/:/,$_,2); # Similarity check my $similar=''; @@ -1863,7 +1906,7 @@ KEYWORDS my $order=&get_order($partid,$respid,$symb,$uname,$udom); if ($env{'form.lastSub'} eq 'lastonly' || ($env{'form.lastSub'} eq 'hdgrade' && - $$handgrade{$part} eq 'yes')) { + $$handgrade{$$part[0].'_'.$$part[1]} eq 'yes')) { my $display_part=&get_display_part($partid,$symb); $lastsubonly.='<tr><td bgcolor="#ffffe6"><b>Part:</b> '. $display_part.' <font color="#999999">( ID '.$respid. @@ -1931,8 +1974,8 @@ KEYWORDS '<input type="hidden" name="newmsg'.$counter.'" value="" />'."\n"; $result.=' <a href="javascript:msgCenter(document.SCORE,'.$counter. ',\''.$msgfor.'\')"; TARGET=_self>'. - &mt('Compose message to student').(scalar(@col_fullnames) >= 1 ? 's' : '').'</a> ('. - &mt('incl. grades').' <input type="checkbox" name="withgrades'.$counter.'" />)'. + &mt('Compose message to student').(scalar(@col_fullnames) >= 1 ? 's' : '').'</a><label> ('. + &mt('incl. grades').' <input type="checkbox" name="withgrades'.$counter.'" /></label>)'. '<img src="'.$request->dir_config('lonIconsURL'). '/mailbkgrd.gif" width="14" height="10" name="mailicon'.$counter.'" />'."\n". '<br /> ('. @@ -1953,8 +1996,10 @@ KEYWORDS my %seen = (); my @partlist; my @gradePartRespid; - for my $part_resp (sort(keys(%$handgrade))) { - my ($partid,$respid) = split(/_/, $part_resp); + my @part_response_id = &flatten_responseType($responseType); + foreach my $part_response_id (@part_response_id) { + my ($partid,$respid) = @{ $part_response_id }; + my $part_resp = join('_',@{ $part_response_id }); next if ($seen{$partid} > 0); $seen{$partid}++; next if ($$handgrade{$part_resp} =~ /:no$/ && $env{'form.lastSub'} =~ /^(hdgrade)$/); @@ -1992,6 +2037,8 @@ KEYWORDS '<input type="button" value="Next" '. 'onClick="javascript:checksubmit(this.form,\'Next\');" TARGET=_self> '; $endform.='(Next and Previous (student) do not save the scores.)'."\n" ; + $endform.="<input type='hidden' value='".&get_increment(). + "' name='increment' />"; $endform.='</td><tr></table></form>'; $endform.=&show_grading_menu_form($symb); $request->print($endform); @@ -2068,6 +2115,7 @@ sub processHandGrade { if ($includemsg =~ /savemsg|newmsg\Q$ctr\E/) { $subject = $env{'form.msgsub'} if ($includemsg =~ /msgsub/); unless ($subject=~/\w/) { $subject=&mt('Grading Feedback'); } + $subject.=' ['.&Apache::lonnet::declutter($url).']'; my (@msgnum) = split(/,/,$includemsg); foreach (@msgnum) { $message.=$env{'form.'.$_} if ($_ =~ /savemsg|newmsg/ && $_ ne ''); @@ -2080,8 +2128,8 @@ sub processHandGrade { "?symb=$symb\">$env{'form.probTitle'}</a>"; } $msgstatus = &Apache::lonmsg::user_normal_msg($uname,$udom, - $subject.' ['. - &Apache::lonnet::declutter($url).']',$message); + $subject, + $message); $request->print('<br />'.&mt('Sending message to [_1]@[_2]',$uname,$udom).': '. $msgstatus); } @@ -2094,11 +2142,11 @@ sub processHandGrade { &saveHandGrade($request,$symb,$collaborator,$udom,$ctr, $env{'form.unamedom'.$ctr},$part); if ($errorflag eq 'not_allowed') { - $request->print("<font color=\"red\">Not allowed to modify grades for $collaborator:$udom</font>"); + $request->print("<span class=\"LC_error\">".&mt('Not allowed to modify grades for [_1]',"$collaborator:$udom")."</span>"); next; } else { if ($message ne '') { - $msgstatus = &Apache::lonmsg::user_normal_msg($collaborator,$udom,$env{'form.msgsub'},$message); + $msgstatus = &Apache::lonmsg::user_normal_msg($collaborator,$udom,$subject,$message); } } } @@ -2290,7 +2338,7 @@ sub saveHandGrade { if (exists($record{'resource.'.$new_part.'.awarded'})) { $newrecord{'resource.'.$new_part.'.awarded'} = ''; } - $newrecord{'resource.'.$new_part.'.regrader'}="$env{'user.name'}:$env{'user.domain'}"; + $newrecord{'resource.'.$new_part.'.regrader'}="$env{'user.name'}:$env{'user.domain'}"; } } elsif ($dropMenu eq 'reset status' && exists($record{'resource.'.$new_part.'.solved'})) { #don't bother if no old records -> no attempts @@ -2326,6 +2374,7 @@ sub saveHandGrade { my $partial= $pts/$wgt; if ($partial eq $record{'resource.'.$new_part.'.awarded'}) { #do not update score for part if not changed. + &handback_files($request,$symb,$stuname,$domain,$newflg,$new_part,\%newrecord); next; } else { push @parts_graded, $new_part; @@ -2349,7 +2398,6 @@ sub saveHandGrade { } $newrecord{'resource.'.$new_part.'.regrader'}= "$env{'user.name'}:$env{'user.domain'}"; - &handback_files($request,$symb,$stuname,$domain,$newflg,$new_part,\%newrecord); } # unless problem has been graded, set flag to version the submitted files unless ($record{'resource.'.$new_part.'.solved'} =~ /^correct_/ || @@ -2364,22 +2412,18 @@ sub saveHandGrade { if (%newrecord) { if (@version_parts) { - my @changed_keys = &version_portfiles(\%record, \@parts_graded, $env{'request.course.id'}, $symb, $domain, $stuname, \@version_parts); + my @changed_keys = &version_portfiles(\%record, \@parts_graded, + $env{'request.course.id'}, $symb, $domain, $stuname, \@version_parts); @newrecord{@changed_keys} = @record{@changed_keys}; + foreach my $new_part (@version_parts) { + &handback_files($request,$symb,$stuname,$domain,$newflg, + $new_part,\%newrecord); + } } &Apache::lonnet::cstore(\%newrecord,$symb, $env{'request.course.id'},$domain,$stuname); - my @ungraded_parts; - foreach my $part (@parts) { - if ( !defined($record{'resource.'.$part.'.awarded'}) - && !defined($newrecord{'resource.'.$part.'.awarded'}) ) { - push(@ungraded_parts, $part); - } - } - if ( !@ungraded_parts ) { - &Apache::bridgetask::remove_from_queue('gradingqueue',$symb,$cdom, - $cnum,$domain,$stuname); - } + &check_and_remove_from_queue(\@parts,\%record,\%newrecord,$symb, + $cdom,$cnum,$domain,$stuname); } if ($aggregateflag) { &Apache::lonnet::cinc('nohist_resourcetracker',\%aggregate, @@ -2388,42 +2432,80 @@ sub saveHandGrade { return ('',$pts,$wgt); } +sub check_and_remove_from_queue { + my ($parts,$record,$newrecord,$symb,$cdom,$cnum,$domain,$stuname) = @_; + my @ungraded_parts; + foreach my $part (@{$parts}) { + if ( $record->{ 'resource.'.$part.'.awarded'} eq '' + && $record->{ 'resource.'.$part.'.solved' } ne 'excused' + && $newrecord->{'resource.'.$part.'.awarded'} eq '' + && $newrecord->{'resource.'.$part.'.solved' } ne 'excused' + ) { + push(@ungraded_parts, $part); + } + } + if ( !@ungraded_parts ) { + &Apache::bridgetask::remove_from_queue('gradingqueue',$symb,$cdom, + $cnum,$domain,$stuname); + } +} + sub handback_files { my ($request,$symb,$stuname,$domain,$newflg,$new_part,$newrecord) = @_; - my $portfolio_root = &Apache::loncommon::propath($domain, - $stuname). - '/userfiles/portfolio'; - my ($partlist,$handgrade,$responseType) = &response_type($symb); - foreach my $part_resp (sort(keys(%$handgrade))) { - my ($part_id, $resp_id) = split(/_/,$part_resp); + my $portfolio_root = &propath($domain,$stuname).'/userfiles/portfolio'; + my ($partlist,$handgrade,$responseType) = &response_type($symb); + + my @part_response_id = &flatten_responseType($responseType); + foreach my $part_response_id (@part_response_id) { + my ($part_id,$resp_id) = @{ $part_response_id }; + my $part_resp = join('_',@{ $part_response_id }); if (($env{'form.'.$newflg.'_'.$part_resp.'_returndoc1'}) && ($new_part == $part_id)) { # if multiple files are uploaded names will be 'returndoc2','returndoc3' my $file_counter = 1; + my $file_msg; while ($env{'form.'.$newflg.'_'.$part_resp.'_returndoc'.$file_counter}) { my $fname=$env{'form.'.$newflg.'_'.$part_resp.'_returndoc'.$file_counter.'.filename'}; my ($directory,$answer_file) = ($env{'form.'.$newflg.'_'.$part_resp.'_origdoc'.$file_counter} =~ /^(.*?)([^\/]*)$/); my ($answer_name,$answer_ver,$answer_ext) = &file_name_version_ext($answer_file); - $directory =~ /^.+$stuname\/portfolio(.*)/; - my $portfolio_path = $1; + my ($portfolio_path) = ($directory =~ /^.+$stuname\/portfolio(.*)/); my @dir_list = &Apache::lonnet::dirlist($portfolio_path,$domain,$stuname,$portfolio_root); my $version = &get_next_version($answer_name, $answer_ext, \@dir_list); - my $new_answer = &version_selected_portfile($domain, $stuname, $portfolio_path, $answer_file, $version); - $$newrecord{"resource.$new_part.$resp_id.handback"} = $new_answer; - # set the filename to match the submitted file name - $env{'form.'.$newflg.'_'.$part_resp.'_returndoc1.filename'} = $env{'form.'.$newflg.'_'.$part_resp.'_origdoc'.$file_counter}; - my $result=&Apache::lonnet::userfileupload($newflg.'_'.$part_resp.'_returndoc'.$file_counter,'', - 'portfolio',undef,undef,undef,$stuname,$domain); + # fix file name + my ($save_file_name) = (($directory.$answer_name.".$version.".$answer_ext) =~ /^.+\/${stuname}\/(.*)/); + my $result=&Apache::lonnet::finishuserfileupload($stuname,$domain, + $newflg.'_'.$part_resp.'_returndoc'.$file_counter, + $save_file_name); if ($result !~ m|^/uploaded/|) { $request->print('<font color="red"> An errror occured ('.$result. - ') while trying to upload '.&display_file().'</font><br />'); - # $request->print(&done('Back')); + ') while trying to upload '.$newflg.'_'.$part_resp.'_returndoc'.$file_counter.'</font><br />'); + } else { + # mark the file as read only + my @files = ($save_file_name); + my @what = ($symb,$env{'request.course.id'},'handback'); + &Apache::lonnet::mark_as_readonly($domain,$stuname,\@files,\@what); + if (exists($$newrecord{"resource.$new_part.$resp_id.handback"})) { + $$newrecord{"resource.$new_part.$resp_id.handback"}.=','; + } + $$newrecord{"resource.$new_part.$resp_id.handback"} .= $save_file_name; + $file_msg.= "\n".'<br /><span class="LC_filename"><a href="/uploaded/'."$domain/$stuname/".$save_file_name.'">'.$save_file_name."</a></span><br />"; + } $request->print("<br />".$fname." will be the uploaded file name"); - $request->print("<font color=\"red\">Will upload document </font>".$env{'form.'.$newflg.'_'.$part_resp.'_origdoc'.$file_counter}); + $request->print(" ".$env{'form.'.$newflg.'_'.$part_resp.'_origdoc'.$file_counter}); $file_counter++; } + my $subject = "File Handed Back by Instructor "; + my $message = "A file has been returned that was originally submitted in reponse to: <br />"; + $message .= "<strong>".&Apache::lonnet::gettitle($symb)."</strong><br />"; + $message .= ' The returned file(s) are named: '. $file_msg; + $message .= " and can be found in your portfolio space."; + my $url = (&Apache::lonnet::decode_symb($symb))[2]; + $url = &Apache::lonnet::declutter($url); + my $msgstatus = &Apache::lonmsg::user_normal_msg($stuname,$domain, + $subject.' (File Returned) ['.$url.']',$message); + } } return; @@ -2509,14 +2591,13 @@ sub version_portfiles { my $version_parts = join('|',@$v_flag); my @returned_keys; my $parts = join('|', @$parts_graded); - my $portfolio_root = &Apache::loncommon::propath($domain, - $stu_name). - '/userfiles/portfolio'; + my $portfolio_root = &propath($domain,$stu_name). + '/userfiles/portfolio'; foreach my $key (keys(%$record)) { my $new_portfiles; if ($key =~ /^resource\.($version_parts)\./ && $key =~ /\.portfiles$/ ) { my @versioned_portfiles; - my @portfiles = split(/,/,$$record{$key}); + my @portfiles = split(/\s*,\s*/,$$record{$key}); foreach my $file (@portfiles) { &Apache::lonnet::unmark_as_readonly($domain,$stu_name,[$symb,$env{'request.course.id'}],$file); my ($directory,$answer_file) =($file =~ /^(.*?)([^\/]*)$/); @@ -2528,7 +2609,7 @@ sub version_portfiles { if ($new_answer ne 'problem getting file') { push(@versioned_portfiles, $directory.$new_answer); &Apache::lonnet::mark_as_readonly($domain,$stu_name, - ['/portfolio'.$directory.$new_answer], + [$directory.$new_answer], [$symb,$env{'request.course.id'},'graded']); } } @@ -2810,16 +2891,18 @@ sub viewgrades { '<table border=0><tr bgcolor="#ffffdd"><td>'; #radio buttons/text box for assigning points for a section or class. #handles different parts of a problem - my ($partlist,$handgrade) = &response_type($symb); + my ($partlist,$handgrade,$responseType) = &response_type($symb); my %weight = (); my $ctsparts = 0; $result.='<table border="0">'; my %seen = (); - for (sort keys(%$handgrade)) { - my ($partid,$respid) = split (/_/,$_,2); + my @part_response_id = &flatten_responseType($responseType); + foreach my $part_response_id (@part_response_id) { + my ($partid,$respid) = @{ $part_response_id }; + my $part_resp = join('_',@{ $part_response_id }); next if $seen{$partid}; $seen{$partid}++; - my $handgrade=$$handgrade{$_}; + my $handgrade=$$handgrade{$part_resp}; my $wgt = &Apache::lonnet::EXT('resource.'.$partid.'.weight',$symb); $weight{$partid} = $wgt eq '' ? '1' : $wgt; @@ -3378,9 +3461,10 @@ sub upcsvScores_form { $result.=$table; $result.='<br /><table width="100%" border="0"><tr><td bgcolor="#777777">'."\n"; $result.='<table width="100%" border="0"><tr bgcolor="#e6ffff"><td>'."\n"; - $result.=' <b>Specify a file containing the class scores for current resource'. + $result.=' <b>'.&mt('Specify a file containing the class scores for current resource'). '.</b></td></tr>'."\n"; $result.='<tr bgcolor=#ffffe6><td>'."\n"; + my $upload=&mt("Upload Scores"); my $upfile_select=&Apache::loncommon::upfile_select_html(); my $ignore=&mt('Ignore First Line'); $result.=<<ENDUPFORM; @@ -3390,11 +3474,13 @@ sub upcsvScores_form { <input type="hidden" name="probTitle" value="$env{'form.probTitle'}" /> <input type="hidden" name="saveState" value="$env{'form.saveState'}" /> $upfile_select -<br /><input type="button" onClick="javascript:checkUpload(this.form);" value="Upload Scores" /> +<br /><input type="button" onClick="javascript:checkUpload(this.form);" value="$upload" /> <label><input type="checkbox" name="noFirstLine" />$ignore</label> </form> ENDUPFORM - $result.='</td></tr></table>'."\n"; + $result.=&Apache::loncommon::help_open_topic("Course_Convert_To_CSV", + &mt("How do I create a CSV file from a spreadsheet")) + .'</td></tr></table>'."\n"; $result.='</td></tr></table><br /><br />'."\n"; $result.=&show_grading_menu_form($symb); return $result; @@ -3510,6 +3596,7 @@ sub csvuploadassign { my ($request)= @_; my ($symb)=&get_symb($request); if (!$symb) {return '';} + my $error_msg = ''; &Apache::loncommon::load_tmp_file($request); my @gradedata = &Apache::loncommon::upfile_record_sep(); if ($env{'form.noFirstLine'}) { shift(@gradedata); } @@ -3562,12 +3649,20 @@ sub csvuploadassign { my $part=$1; my $wgt =&Apache::lonnet::EXT('resource.'.$part.'.weight', $symb,$domain,$username); - $entries{$fields{$dest}}=~s/\s//g; - my $pcr=$entries{$fields{$dest}} / $wgt; - my $award='correct_by_override'; - $grades{"resource.$part.awarded"}=$pcr; - $grades{"resource.$part.solved"}=$award; - $points{$part}=1; + if ($wgt) { + $entries{$fields{$dest}}=~s/\s//g; + my $pcr=$entries{$fields{$dest}} / $wgt; + my $award='correct_by_override'; + $grades{"resource.$part.awarded"}=$pcr; + $grades{"resource.$part.solved"}=$award; + $points{$part}=1; + } else { + $error_msg = "<br />" . + &mt("Some point values were assigned" + ." for problems with a weight " + ."of zero. These values were " + ."ignored."); + } } else { if ($dest=~/stores_(.*)_awarded/) { if ($points{$1}) {next;} } if ($dest=~/stores_(.*)_solved/) { if ($points{$1}) {next;} } @@ -3607,7 +3702,7 @@ sub csvuploadassign { } $request->print("<br />\n"); $request->print(&show_grading_menu_form($symb)); - return ''; + return $error_msg; } #------------- end of section for handling csv file upload --------- # @@ -3713,8 +3808,8 @@ LISTJAVASCRIPT $studentTable.=($ptr%2 == 0 ? '</td></tr>' : ''); $ptr++; } - $studentTable.='</td><td> </td><td> ' if ($ptr%2 == 0); - $studentTable.='</td></tr></table></td></tr></table>'."\n"; + $studentTable.='</td><td> </td><td> </td></tr>' if ($ptr%2 == 0); + $studentTable.='</table></td></tr></table>'."\n"; $studentTable.='<input type="button" '. 'onClick="javascript:checkPickOne(this.form);"value="Next->" /></form>'."\n"; @@ -3737,9 +3832,10 @@ sub getSymbMap { 1,0,1); for my $sequence ($navmap->getById('0.0'), @sequences) { if ($navmap->hasResource($sequence, sub { shift->is_problem(); }, 0) ) { - my $title = $minder.'.'.$sequence->compTitle(); - push @titles, $title; # minder in case two titles are identical - $symbx{$title} = $sequence->symb(); + my $title = $minder.'.'. + &HTML::Entities::encode($sequence->compTitle(),'"\'&'); + push(@titles, $title); # minder in case two titles are identical + $symbx{$title} = &HTML::Entities::encode($sequence->symb(),'"\'&'); $minder++; } } @@ -3799,7 +3895,8 @@ sub displayPage { '<input type="hidden" name="overRideScore" value="no" />'."\n". '<input type="hidden" name="saveState" value="'.$env{'form.saveState'}.'" />'."\n"; - my $checkIcon = '<img src="'.$request->dir_config('lonIconsURL'). + my $checkIcon = '<img alt="'.&mt('Check Mark'). + '" src="'.$request->dir_config('lonIconsURL'). '/check.gif" height="16" border="0" />'; $studentTable.=' <b>Note:</b> Problems graded correct by the computer are marked with a '.$checkIcon. @@ -3879,9 +3976,9 @@ sub displayPage { $curRes = $iterator->next(); } - $studentTable.='</td></tr></table></td></tr></table>'."\n". + $studentTable.='</table></td></tr></table>'."\n". '<input type="button" value="Save" '. - 'onClick="javascript:checkSubmitPage(this.form,'.$question.');" TARGET=_self />'. + 'onClick="javascript:checkSubmitPage(this.form,'.$question.');" />'. '</form>'."\n"; $studentTable.=&show_grading_menu_form($symb); $request->print($studentTable); @@ -3987,7 +4084,7 @@ sub displaySubByDates { if ($displaySub[2]) { $studentTable.='Manually graded by '.$displaySub[2]; } - $studentTable.=' </td></tr>'; + $studentTable.=' </td></tr>3'; } $studentTable.='</table></td></tr></table>'; @@ -4096,9 +4193,8 @@ sub updateGradeByPage { $displayPts[1].=' <b>Part:</b> '.$display_part.' = '. (($score eq 'excused') ? 'excused' : $newpts). ' <br />'; - $question++; - next if ($dropMenu eq 'reset status' || ($newpts == $oldpts && $score ne 'excused')); + next if ($dropMenu eq 'reset status' || ($newpts eq $oldpts && $score ne 'excused')); $newrecord{'resource.'.$partid.'.awarded'} = $partial if $partial ne ''; $newrecord{'resource.'.$partid.'.solved'} = $score if $score ne ''; @@ -4110,7 +4206,12 @@ sub updateGradeByPage { if (scalar(keys(%newrecord)) > 0) { &Apache::lonnet::cstore(\%newrecord,$symbx,$env{'request.course.id'}, $udom,$uname); + my %record = &Apache::lonnet::restore($symbx,$env{'request.course.id'}, + $udom,$uname); + &check_and_remove_from_queue($parts,\%record,undef,$symbx, + $cdom,$cnum,$udom,$uname); } + if ($aggregateflag) { &Apache::lonnet::cinc('nohist_resourcetracker',\%aggregate, $env{'course.'.$env{'request.course.id'}.'.domain'}, @@ -4173,7 +4274,7 @@ sub scantron_filenames { my $cdom=$env{'course.'.$env{'request.course.id'}.'.domain'}; my $cname=$env{'course.'.$env{'request.course.id'}.'.num'}; my @files=&Apache::lonnet::dirlist('userfiles',$cdom,$cname, - &Apache::loncommon::propath($cdom,$cname)); + &propath($cdom,$cname)); my @possiblenames; foreach my $filename (sort(@files)) { ($filename)=split(/&/,$filename); @@ -4224,14 +4325,14 @@ sub scantron_CODElist { } sub scantron_CODEunique { - my $result='<nobr> + my $result='<span style="white-space: nowrap;"> <label><input type="radio" name="scantron_CODEunique" value="yes" checked="checked" /> Yes </label> - </nobr> - <nobr> + </span> + <span style="white-space: nowrap;"> <label><input type="radio" name="scantron_CODEunique" value="no" /> No </label> - </nobr>'; + </span>'; return $result; } @@ -4350,6 +4451,7 @@ SCANTRONFORM <tr> <form action='/adm/grades' name='scantron_download'> <td bgcolor="#777777"> + $default_form_data <input type="hidden" name="command" value="scantron_download" /> <table width="100%" border="0"> <tr bgcolor="#e6ffff"> @@ -4532,7 +4634,8 @@ sub scantron_parse_scanline { substr($questions,0,$$scantron_config{'Qlength'})=''; if (length($currentquest) < $$scantron_config{'Qlength'}) { next; } if ($$scantron_config{'Qon'} eq 'letter') { - if ($currentquest eq '?') { + if ($currentquest eq '?' + || $currentquest eq '*') { push(@{$record{'scantron.doubleerror'}},$questnum); $record{"scantron.$questnum.answer"}=''; } elsif (!$currentquest @@ -4546,7 +4649,8 @@ sub scantron_parse_scanline { $record{"scantron.$questnum.answer"}=$currentquest; } } elsif ($$scantron_config{'Qon'} eq 'number') { - if ($currentquest eq '?') { + if ($currentquest eq '?' + || $currentquest eq '*') { push(@{$record{'scantron.doubleerror'}},$questnum); $record{"scantron.$questnum.answer"}=''; } elsif (!$currentquest @@ -4557,8 +4661,14 @@ sub scantron_parse_scanline { push(@{$record{"scantron.missingerror"}},$questnum); } } else { - $record{"scantron.$questnum.answer"}= - $alphabet[$currentquest-1]; + # wrap zero back to J + if ($currentquest eq '0') { + $record{"scantron.$questnum.answer"}= + $alphabet[9]; + } else { + $record{"scantron.$questnum.answer"}= + $alphabet[$currentquest-1]; + } } } else { my @array=split($$scantron_config{'Qon'},$currentquest,-1); @@ -4688,21 +4798,29 @@ sub reset_skipping_status { &scantron_putfile(undef,$scan_data); } -sub allow_skipping { +sub start_skipping { my ($scan_data,$i)=@_; my %remembered=split(':',&scan_data($scan_data,'remember_skipping')); - delete($remembered{$i}); + if ($env{'form.scantron_options_redo'} =~ /^redo_/) { + $remembered{$i}=2; + } else { + $remembered{$i}=1; + } &scan_data($scan_data,'remember_skipping',join(':',%remembered)); } sub should_be_skipped { - my ($scan_data,$i)=@_; + my ($scanlines,$scan_data,$i)=@_; if ($env{'form.scantron_options_redo'} !~ /^redo_/) { # not redoing old skips + if ($scanlines->{'skipped'}[$i]) { return 1; } return 0; } my %remembered=split(':',&scan_data($scan_data,'remember_skipping')); - if (exists($remembered{$i})) { return 0; } + + if (exists($remembered{$i}) && $remembered{$i} != 2 ) { + return 0; + } return 1; } @@ -4714,6 +4832,7 @@ sub remember_current_skipped { $to_remember{$i}=1; } } + &scan_data($scan_data,'remember_skipping',join(':',%to_remember)); &scantron_putfile(undef,$scan_data); } @@ -4729,15 +4848,15 @@ sub scantron_warning_screen { my ($button_text)=@_; my $title=&Apache::lonnet::gettitle($env{'form.selectpage'}); my %scantron_config=&get_scantron_config($env{'form.scantron_format'}); - my $CODElist="a"; + my $CODElist; if ($scantron_config{'CODElocation'} && $scantron_config{'CODEstart'} && $scantron_config{'CODElength'}) { $CODElist=$env{'form.scantron_CODElist'}; - if ($CODElist eq '') { $CODElist='<font color="red">None</font>'; } + if ($env{'form.scantron_CODElist'} eq '') { $CODElist='<font color="red">None</font>'; } $CODElist= '<tr><td><b>List of CODES to validate against:</b></td><td><tt>'. - $CODElist.'</tt></td></tr>'; + $env{'form.scantron_CODElist'}.'</tt></td></tr>'; } return (<<STUFF); <p> @@ -4785,7 +4904,7 @@ $warning <input type="hidden" name="command" value="scantron_validate" /> STUFF } - $r->print("</form><br />".&show_grading_menu_form($symb)."</body></html>"); + $r->print("</form><br />".&show_grading_menu_form($symb)); return ''; } @@ -4819,7 +4938,6 @@ sub scantron_validate_file { } if ($env{'form.scantron_options_redo'} eq 'redo_skipped') { &remember_current_skipped(); - &scantron_remove_file('skipped'); $env{'form.scantron_options_redo'}='redo_skipped_ready'; } @@ -4886,8 +5004,7 @@ STUFF $r->print(" this scanline saving it for later."); } } - $r->print(" </form><br />".&show_grading_menu_form($symb). - "</body></html>"); + $r->print(" </form><br />".&show_grading_menu_form($symb)); return ''; } @@ -4990,8 +5107,8 @@ sub scantron_putfile { sub scantron_get_line { my ($scanlines,$scan_data,$i)=@_; - if (&should_be_skipped($scan_data,$i)) { return undef; } - if ($scanlines->{'skipped'}[$i]) { return undef; } + if (&should_be_skipped($scanlines,$scan_data,$i)) { return undef; } + #if ($scanlines->{'skipped'}[$i]) { return undef; } if ($scanlines->{'corrected'}[$i]) {return $scanlines->{'corrected'}[$i];} return $scanlines->{'orig'}[$i]; } @@ -5011,12 +5128,21 @@ sub scantron_put_line { my ($scanlines,$scan_data,$i,$newline,$skip)=@_; if ($skip) { $scanlines->{'skipped'}[$i]=$newline; - &allow_skipping($scan_data,$i); + &start_skipping($scan_data,$i); return; } $scanlines->{'corrected'}[$i]=$newline; } +sub scantron_clear_skip { + my ($scanlines,$scan_data,$i)=@_; + if (exists($scanlines->{'skipped'}[$i])) { + undef($scanlines->{'skipped'}[$i]); + return 1; + } + return 0; +} + sub scantron_filter_not_exam { my ($curres)=@_; @@ -5048,7 +5174,7 @@ sub scantron_validate_sequence { my @resources= $navmap->retrieveResources($map,\&scantron_filter_not_exam,1,0); if (@resources) { - $r->print("<p>".&mt('Some resource in the sequece currently are not set to exam mode. Grading these resources currently may not work correctly.')."</p>"); + $r->print("<p>".&mt('Some resources in the sequence currently are not set to exam mode. Grading these resources currently may not work correctly.')."</p>"); return (1,$currentphase); } } @@ -5202,11 +5328,11 @@ function change_radio(field) { </script> ENDSCRIPT my $href="/adm/pickcode?". - "form=".&Apache::lonnet::escape("scantronupload"). - "&scantron_format=".&Apache::lonnet::escape($env{'form.scantron_format'}). - "&scantron_CODElist=".&Apache::lonnet::escape($env{'form.scantron_CODElist'}). - "&curCODE=".&Apache::lonnet::escape($$scan_record{'scantron.CODE'}). - "&scantron_selectfile=".&Apache::lonnet::escape($env{'form.scantron_selectfile'}); + "form=".&escape("scantronupload"). + "&scantron_format=".&escape($env{'form.scantron_format'}). + "&scantron_CODElist=".&escape($env{'form.scantron_CODElist'}). + "&curCODE=".&escape($$scan_record{'scantron.CODE'}). + "&scantron_selectfile=".&escape($env{'form.scantron_selectfile'}); if ($env{'form.scantron_CODElist'} =~ /\S/) { $r->print("<label><input type='radio' name='scantron_CODE_resolution' value='use_found' /> <a target='_blank' href='$href'>Select</a> a CODE from the list of all CODEs and use it.</label> Selected CODE is <input readonly='true' type='text' size='8' name='scantron_CODE_selectedvalue' onfocus=\"javascript:change_radio('use_found')\" onchange=\"javascript:change_radio('use_found')\" />"); $r->print("\n<br />"); @@ -5503,6 +5629,10 @@ SCANTRONFORM &Apache::lonxml::clear_problem_counter(); &Apache::lonnet::appenv(%$scan_record); + + if (&scantron_clear_skip($scanlines,$scan_data,$i)) { + &scantron_putfile($scanlines,$scan_data); + } my $i=0; foreach my $resource (@resources) { @@ -5890,7 +6020,7 @@ sub handler { if ($#commands > 0) { &Apache::lonnet::logthis("grades got multiple commands ".join(':',@commands)); } - &send_header($request); + $request->print(&Apache::loncommon::start_page('Grading')); if ($symb eq '' && $command eq '') { if ($env{'user.adv'}) { if (($env{'form.codeone'}) && ($env{'form.codetwo'}) && @@ -5981,20 +6111,8 @@ sub handler { $request->print("Access Denied ($command)"); } } - &send_footer($request); - return ''; -} - -sub send_header { - my ($request)= @_; - &Apache::lontexconvert::init_tth(); - $request->print(&Apache::loncommon::start_page('Grading')); - $request->rflush(); -} - -sub send_footer { - my ($request)= @_; $request->print(&Apache::loncommon::end_page()); + return ''; } 1;