--- loncom/homework/grades.pm 2002/08/02 21:10:03 1.44 +++ loncom/homework/grades.pm 2002/10/02 21:24:35 1.53 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # The LON-CAPA Grading handler # -# $Id: grades.pm,v 1.44 2002/08/02 21:10:03 ng Exp $ +# $Id: grades.pm,v 1.53 2002/10/02 21:24:35 albertel Exp $ # # Copyright Michigan State University Board of Trustees # @@ -103,17 +103,6 @@ sub response_type { return \@partlist,\%handgrade; } -#--- Prints a message on screen if a user did something wrong -#--- Operator error --- -sub userError { - my ($request, $reason, $step) = @_; - $request->print('<h3><font color="red">LON-CAPA User Error</font></h3><br />'."\n"); - $request->print('<b>Reason: </b>'.$reason.'<br /><br />'."\n"); - $request->print('<b>Step: </b>'.($step ne '' ? $step : 'Use your browser back button to correct') - .'<br /><br />'."\n"); - return ''; -} - #--- Dumps the class list with usernames,list of sections, #--- section, ids and fullnames for each user. sub getclasslist { @@ -122,6 +111,10 @@ sub getclasslist { my %classlist=&Apache::lonnet::dump('classlist', $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}, $ENV{'course.'.$ENV{'request.course.id'}.'.num'}); + my ($tmp) = keys(%classlist); + # Bail out if we were unable to get the classlist + return if ($tmp =~ /^(con_lost|error|no_such_host)/i); + # codes to check for fields in the classlist # should contain end:start:id:section:fullname for (keys %classlist) { @@ -224,11 +217,33 @@ sub student_gradeStatus { return %partstatus; } +# hidden form and javascript that calls the form +# Use by verifyscript and viewgrades +# Shows a student's view of problem and submission +sub jscriptNform { + my ($url,$symb) = @_; + my $jscript='<script type="text/javascript" language="javascript">'."\n". + ' function viewOneStudent(user,domain) {'."\n". + ' document.onestudent.student.value = user;'."\n". + ' document.onestudent.userdom.value = domain;'."\n". + ' document.onestudent.submit();'."\n". + ' }'."\n". + '</script>'."\n"; + $jscript.= '<form action="/adm/grades" method="post" name="onestudent">'."\n". + '<input type="hidden" name="symb" value="'.$symb.'" />'."\n". + '<input type="hidden" name="url" value="'.$url.'" />'."\n". + '<input type="hidden" name="command" value="submission" />'."\n". + '<input type="hidden" name="student" value="" />'."\n". + '<input type="hidden" name="userdom" value="" />'."\n". + '</form>'."\n"; + return $jscript; +} #------------------ End of general use routines -------------------- #------------------------------------------------------------------- #------------------------------------ Receipt Verification Routines +# #--- Check whether a receipt number is valid.--- sub verifyreceipt { my $request = shift; @@ -243,29 +258,14 @@ sub verifyreceipt { $symb = &Apache::lonnet::symbread($url); } - my $jscript='<script type="text/javascript" language="javascript">'."\n". - ' function viewOneStudent(user,domain) {'."\n". - ' document.onestudent.student.value = user;'."\n". - ' document.onestudent.userdom.value = domain;'."\n". - ' document.onestudent.submit();'."\n". - ' }'."\n". - '</script>'."\n"; - $jscript.= '<form action="/adm/grades" method="post" name="onestudent">'."\n". - '<input type="hidden" name="symb" value="'.$symb.'" />'."\n". - '<input type="hidden" name="url" value="'.$url.'" />'."\n". - '<input type="hidden" name="command" value="submission" />'."\n". - '<input type="hidden" name="student" value="" />'."\n". - '<input type="hidden" name="userdom" value="" />'."\n". - '</form>'."\n"; - - my $title.='<h2><font color="#339933">Verifying Submission Receipt '. - $receipt.'</h2></font>'."\n". + my $title.='<h3><font color="#339933">Verifying Submission Receipt '. + $receipt.'</h3></font>'."\n". '<font size=+1><b>Resource: </b>'.$ENV{'form.url'}.'</font><br><br>'."\n"; my ($string,$contents,$matches) = ('','',0); my ($classlist,$seclist,$ids,$stusec,$fullname) = &getclasslist('all','0'); - foreach (sort {$$fullname{$a} cmp $$fullname{$b} } keys %$fullname) { + foreach (sort {lc($$fullname{$a}) cmp lc($$fullname{$b}) } keys %$fullname) { my ($uname,$udom)=split(/\:/); if ($receipt eq &Apache::lonnet::ireceipt($uname,$udom,$courseid,$symb)) { @@ -281,7 +281,7 @@ sub verifyreceipt { if ($matches == 0) { $string = $title.'No match found for the above receipt.'; } else { - $string = $jscript.$title. + $string = &jscriptNform($url,$symb).$title. 'The above receipt matches the following student'. ($matches <= 1 ? '.' : 's.')."\n". '<table border="0"><tr><td bgcolor="#777777">'."\n". @@ -292,7 +292,7 @@ sub verifyreceipt { $contents. '</table></td></tr></table>'."\n"; } - return $string.&show_grading_menu_form ($symb,$url); + return $string.&show_grading_menu_form($symb,$url); } #--- This is called by a number of programs. @@ -301,17 +301,15 @@ sub verifyreceipt { # on the problem page. sub listStudents { my ($request) = shift; + + my ($symb,$url) = &get_symb_and_url(); my $cdom = $ENV{"course.$ENV{'request.course.id'}.domain"}; my $cnum = $ENV{"course.$ENV{'request.course.id'}.num"}; my $getsec = $ENV{'form.section'} eq '' ? 'all' : $ENV{'form.section'}; my $submitonly= $ENV{'form.submitonly'} eq '' ? 'all' : $ENV{'form.submitonly'}; - my $result='<h2><font color="#339933"> '. - 'View Submissions for a Student or a Group of Students</font></h2>'; - $result.='<table border="0">'; - $result.='<tr><td colspan=3><font size=+1>'. - '<b>Resource: </b>'.$ENV{'form.url'}.'</font></td></tr>'; - my ($partlist,$handgrade) = &response_type($ENV{'form.url'}); + my $result; + my ($partlist,$handgrade) = &response_type($url); for (sort keys(%$handgrade)) { my ($responsetype,$handgrade)=split(/:/,$$handgrade{$_}); $ENV{'form.handgrade'} = 'yes' if ($handgrade eq 'yes'); @@ -320,62 +318,108 @@ sub listStudents { '<td><b>Handgrade: </b>'.$handgrade.'</font></td></tr>'; } $result.='</table>'; - $request->print($result); - $request->print(<<ENDTABLEST); -<form action="/adm/grades" method="post"> - <b>View Problem: </b><input type="radio" name="vProb" value="no" checked> no -<input type="radio" name="vProb" value="yes"> yes <br /> - <b>Submissions: </b> -<input type="radio" name="lastSub" value="hdgrade" checked /> handgrade only -<input type="radio" name="lastSub" value="lastonly" /> last sub only -<input type="radio" name="lastSub" value="last" /> last sub & parts info -<input type="radio" name="lastSub" value="all" /> all details -<input type="hidden" name="section" value="$getsec" /> -<input type="hidden" name="submitonly" value="$submitonly" /> -<input type="hidden" name="response" value="$ENV{'form.response'}" /> -<input type="hidden" name="handgrade" value="$ENV{'form.handgrade'}" /><br /> -<input type="hidden" name="showgrading" value="$ENV{'form.showgrading'}" /><br /> -<input type="submit" name="submit" value="View/Grade" /> -ENDTABLEST - if ($ENV{'form.url'}) { - $request->print('<input type="hidden" name="url" value="'.$ENV{'form.url'}.'" />'."\n"); + my $viewgrade; + if ($ENV{'form.handgrade'} eq 'yes') { + $viewgrade = 'View/Grade'; + } else { + $viewgrade = 'View'; } - if ($ENV{'form.symb'}) { - $request->print('<input type="hidden" name="symb" value="'.$ENV{'form.symb'}.'" />'."\n"); + + $result='<h3><font color="#339933"> '. + $viewgrade. + ' Submissions for a Student or a Group of Students</font></h3>'. + '<table border="0"><tr><td colspan=3><font size=+1>'. + '<b>Resource: </b>'.$url.'</font></td></tr>'.$result; + + $request->print(<<LISTJAVASCRIPT); +<script type="text/javascript" language="javascript"> + function checkSelect(checkBox) { + var ctr=0; + var sense=""; + if (checkBox.length > 1) { + for (var i=0; i<checkBox.length; i++) { + if (checkBox[i].checked) { + ctr++; + } + } + sense = "a student or group of students"; + } else { + if (checkBox.checked) { + ctr = 1; + } + sense = "the student"; } - $request->print('<input type="hidden" name="command" value="processGroup" />'."\n"); + if (ctr == 0) { + alert("Please select "+sense+" before clicking on the $viewgrade button."); + return false; + } + document.gradesub.submit(); + } +</script> +LISTJAVASCRIPT + + $request->print($result); + + my $checkhdgrade = $ENV{'form.handgrade'} eq 'yes' ? 'checked' : ''; + my $checklastsub = $ENV{'form.handgrade'} eq 'yes' ? '' : 'checked'; + my $gradeTable='<form action="/adm/grades" method="post" name="gradesub">'."\n". + ' <b>View Problem: </b><input type="radio" name="vProb" value="no" checked> no '."\n". + '<input type="radio" name="vProb" value="yes"> yes <br />'."\n". + ' <b>Submissions: </b>'."\n"; + if ($ENV{'form.handgrade'} eq 'yes') { + $gradeTable.='<input type="radio" name="lastSub" value="hdgrade" '.$checkhdgrade.' /> handgrade only'."\n"; + } + $gradeTable.='<input type="radio" name="lastSub" value="lastonly" '.$checklastsub.' /> last sub only'."\n". + '<input type="radio" name="lastSub" value="last" /> last sub & parts info'."\n". + '<input type="radio" name="lastSub" value="all" /> all details'."\n". + '<input type="hidden" name="section" value="'.$getsec.'" />'."\n". + '<input type="hidden" name="submitonly" value="'.$submitonly.'" />'."\n". + '<input type="hidden" name="response" value="'.$ENV{'form.response'}.'" />'."\n". + '<input type="hidden" name="handgrade" value="'.$ENV{'form.handgrade'}.'" /><br />'."\n". + '<input type="hidden" name="showgrading" value="'.$ENV{'form.showgrading'}.'" /><br />'."\n". + '<input type="hidden" name="url" value="'.$url.'" />'."\n". + '<input type="hidden" name="symb" value="'.$symb.'" />'."\n". + 'To '.lc($viewgrade).' a submission, click on the check box next to the student\'s name. Then '."\n". + 'click on the '.$viewgrade.' button. To view the submissions for a group of students, click'."\n". + ' on the check boxes for the group of students.<br />'."\n". + '<input type="hidden" name="command" value="processGroup" />'."\n". + '<input type="button" '."\n". + 'onClick="javascript:checkSelect(this.form.stuinfo);" '."\n". + 'value="'.$viewgrade.'" />'."\n"; + my ($classlist,$seclist,$ids,$stusec,$fullname) = &getclasslist($getsec,'0'); - $result='<table border="0"><tr><td bgcolor="#777777">'. + $gradeTable.='<table border="0"><tr><td bgcolor="#777777">'. '<table border="0"><tr bgcolor="#e6ffff">'. '<td><b> Select </b></td><td><b> Fullname </b></td>'. '<td><b> Username </b></td><td><b> Domain </b></td>'; foreach (sort(@$partlist)) { - $result.='<td><b> Part '.(split(/_/))[0].' Status </b></td>'; + $gradeTable.='<td><b> Part '.(split(/_/))[0].' Status </b></td>'; } - $request->print($result.'</tr>'."\n"); + $gradeTable.='</tr>'."\n"; - foreach my $student (sort {$$fullname{$a} cmp $$fullname{$b} } keys %$fullname) { + my $ctr = 0; + foreach my $student (sort {lc($$fullname{$a}) cmp lc($$fullname{$b}) } keys %$fullname) { my ($uname,$udom) = split(/:/,$student); - my (%status) = &student_gradeStatus($ENV{'form.url'}, - $ENV{'form.symb'},$udom,$uname,$partlist); + my (%status) =&student_gradeStatus($url,$symb,$udom,$uname,$partlist); my $statusflg = ''; foreach (keys(%status)) { $statusflg = 1 if ($status{$_} ne 'nothing'); my ($foo,$partid,$foo1) = split(/\./,$_); if ($status{'resource.'.$partid.'.submitted_by'} ne '') { $statusflg = ''; - $request->print('<input type="hidden" name="'. - $student.':submitted_by" value="'. - $status{'resource.'.$partid.'.submitted_by'}.'" />'); + $gradeTable.='<input type="hidden" name="'. + $student.':submitted_by" value="'. + $status{'resource.'.$partid.'.submitted_by'}.'" />'; } } next if ($statusflg eq '' && $submitonly eq 'yes'); + $ctr++; if ( $Apache::grades::viewgrades eq 'F' ) { - $result='<tr bgcolor="#ffffe6">'. + $gradeTable.='<tr bgcolor="#ffffe6">'. '<td align="center"><input type=checkbox name="stuinfo" value="'. $student.':'.$$fullname{$student}.'"></td>'."\n". '<td> '.$$fullname{$student}.' </td>'."\n". @@ -384,13 +428,23 @@ ENDTABLEST foreach (sort keys(%status)) { next if (/^resource.*?submitted_by$/); - $result.='<td align="middle"> '.$status{$_}.' </td>'."\n"; + $gradeTable.='<td align="middle"> '.$status{$_}.' </td>'."\n"; } - $request->print($result.'</tr>'."\n"); + $gradeTable.='</tr>'."\n"; } } - $request->print('</table></td></tr></table>'); - $request->print('<input type="submit" name="submit" value="View/Grade" /><form />'); + $gradeTable.='</table></td></tr></table>'. + '<input type="button" '. + 'onClick="javascript:checkSelect(this.form.stuinfo);" '. + 'value="'.$viewgrade.'" /></form>'."\n"; + if ($ctr == 0) { + $gradeTable='<br /> <font color="red">'. + 'No submission found for this resource.</font><br />'; + } elsif ($ctr == 1) { + $gradeTable =~ s/type=checkbox/type=checkbox checked/; + } + $gradeTable.=&show_grading_menu_form($symb,$url); + $request->print($gradeTable); return ''; } @@ -402,10 +456,7 @@ sub processGroup { my @stuchecked = (ref($ENV{'form.stuinfo'}) ? @{$ENV{'form.stuinfo'}} : ($ENV{'form.stuinfo'})); my $total = scalar(@stuchecked)-1; - if ($stuchecked[0] eq '') { - &userError($request,'No student was selected for viewing/grading.'); - return; - } + foreach (@stuchecked) { my ($uname,$udom,$fullname) = split(/:/); $ENV{'form.student'} = $uname; @@ -489,6 +540,30 @@ sub sub_page_js { return; } +//=================== Check that a point is assigned for all the parts ============== + function checksubmit(val,total,parttot) { + document.SCORE.gradeOpt.value = val; + if (val == "Save & Next") { + for (i=0;i<=total;i++) { + for (j=0;j<parttot;j++) { + var partid = eval("document.SCORE.partid"+i+"_"+j+".value"); + var selopt = eval("document.SCORE.GD_SEL"+i+"_"+partid); + if (selopt[0].selected) { + var points = eval("document.SCORE.GD_BOX"+i+"_"+partid+".value"); + if (points == "") { + var name = eval("document.SCORE.name"+i+".value"); + alert("Please assign a score for "+name+", part "+partid+"."); + return false; + } + } + + } + } + + } + document.SCORE.submit(); + } + //===================== Show list of keywords ==================== function keywords(keyform) { var keywds = keyform.value; @@ -519,7 +594,7 @@ sub sub_page_js { else return; var cleantxt = txt.replace(new RegExp('([\\f\\n\\r\\t\\v ])+', 'g')," "); if (cleantxt=="") { - alert("Select a word or group of words from document and then click this link."); + alert("Please select a word or group of words from document and then click this link."); return; } var nret = prompt("Add selection to keyword list? Edit if desired.",cleantxt); @@ -766,8 +841,8 @@ sub submission { # header info if ($counter == 0) { &sub_page_js($request); - $request->print('<h2> <font color="#339933">Submission Record</font></h2>'. - '<font size=+1> <b>Resource: </b>'.$url.'</font>'); + $request->print('<h3> <font color="#339933">Submission Record</font></h3>'."\n". + '<font size=+1> <b>Resource: </b>'.$url.'</font>'."\n"); # option to display problem, only once else it cause problems # with the form later since the problem has a form. @@ -778,7 +853,7 @@ sub submission { $ENV{'request.course.id'}); my $result.='<table border="0" width="100%"><tr><td bgcolor="#777777">'; $result.='<table border="0" width="100%"><tr><td bgcolor="#e6ffff">'; - $result.='<b> View of the problem for '.$ENV{'form.fullname'}. + $result.='<b> View of the problem - '.$ENV{'form.fullname'}. '</b></td></tr><tr><td bgcolor="#ffffff">'.$rendered.'<br />'; $result.='<b>Correct answer:</b><br />'.$companswer; $result.='</td></tr></table>'; @@ -851,16 +926,17 @@ KEYWORDS # Display student info $request->print(($counter == 0 ? '' : '<br />')); - my $result='<table border="0" width=100%><tr><td bgcolor="#777777">'. - '<table border="0" width=100%><tr bgcolor="#edffff"><td>'; + my $result='<table border="0" width=100%><tr><td bgcolor="#777777">'."\n". + '<table border="0" width=100%><tr bgcolor="#edffff"><td>'."\n"; -# $result.='<table border="0"><tr bgcolor="#ffffff"><td><b>Fullname: </b>'.$ENV{'form.fullname'}. $result.='<b>Fullname: </b>'.$ENV{'form.fullname'}. '<font color="#999999"> Username: '.$uname.'</font>'. - '<font color="#999999"> Domain: '.$udom.'</font><br />'; + '<font color="#999999"> Domain: '.$udom.'</font><br />'."\n"; + $result.='<input type="hidden" name="name'.$counter. + '" value="'.$ENV{'form.fullname'}.'" />'."\n"; # If this is handgraded, then check for collaborators - my $col_flag = 0; + my @col_fullnames; if ($ENV{'form.handgrade'} eq 'yes') { my @col_list; ($classlist,$seclist,$ids,$stusec,$fullname) = &getclasslist('all','0'); @@ -883,8 +959,9 @@ KEYWORDS push @badcollaborators,$collaborator; next; } - $col_flag++; push @col_list, $collaborator; + my ($lastname,$givenn) = split(/,/,$$fullname{$collaborator.':'.$udom}); + push @col_fullnames, $givenn.' '.$lastname; $result.=$$fullname{$collaborator.':'.$udom}.' '; } $result.='<br />'."\n"; @@ -924,12 +1001,12 @@ KEYWORDS $request->print($submitby); } else { my ($string,$timestamp)= - &get_last_submission ($symb,$uname,$udom,$ENV{'request.course.id'}); + &get_last_submission (%record); my $lastsubonly.=''. ($$timestamp eq '' ? '' : '<b>Date Submitted:</b> '. $$timestamp).''; if ($$timestamp eq '') { - $lastsubonly.='<tr><td bgcolor="#ffffe6">'.$$string[0].'</td></tr>'; + $lastsubonly.='<tr><td bgcolor="#ffffe6">'.$$string[0].'</td></tr>'."\n"; } else { for my $part (sort keys(%$handgrade)) { foreach (@$string) { @@ -939,7 +1016,7 @@ KEYWORDS $lastsubonly.='<tr><td bgcolor="#ffffe6"><b>Part '. $partid.'</b> <font color="#999999">( ID '.$respid. ' )</font> <b>Answer: </b>'. - &keywords_highlight($subval).'</td></tr>' + &keywords_highlight($subval).'</td></tr>'."\n" if ($ENV{'form.lastSub'} eq 'lastonly' || ($ENV{'form.lastSub'} eq 'hdgrade' && $$handgrade{$part} =~ /:yes$/)); @@ -947,7 +1024,7 @@ KEYWORDS } } } - $lastsubonly.='</td></tr><tr><td bgcolor="#ffffff">'."\n"; + $lastsubonly.='</td></tr>'."\n"; $request->print($lastsubonly); } } else { @@ -959,17 +1036,25 @@ KEYWORDS # return if view submission with no grading option if ($ENV{'form.showgrading'} eq '') { - $request->print('</td></tr></table></td></tr></table></form>'); + $request->print('</td></tr></table></td></tr></table></form>'."\n"); return; } # Grading options $result='<input type="hidden" name="newmsg'.$counter.'" value="" />'."\n". '<input type="hidden" name="includemsg'.$counter.'" value="" />'."\n". - '<input type="hidden" name="unamedom'.$counter.'" value="'.$uname.':'.$udom.'" />'."\n"; - $result.=' <a href="javascript:msgCenter(document.SCORE,'.$counter. - ',\''.$ENV{'form.fullname'}.'\')"; TARGET=_self>'. - 'Compose Message to student'.($col_flag > 1 ? 's' : '').'</a>'. + '<input type="hidden" name="unamedom'.$counter.'" value="'.$uname.':' + .$udom.'" />'."\n"; + my ($lastname,$givenn) = split(/,/,$ENV{'form.fullname'}); + my $msgfor = $givenn.' '.$lastname; + if (scalar(@col_fullnames) > 0) { + my $lastone = pop @col_fullnames; + $msgfor .= ', '.(join ', ',@col_fullnames).' and '.$lastone.'.'; + } + $result.='<tr><td bgcolor="#ffffff">'."\n". + ' <a href="javascript:msgCenter(document.SCORE,'.$counter. + ',\''.$msgfor.'\')"; TARGET=_self>'. + 'Compose Message to student'.(scalar(@col_fullnames) >= 1 ? 's' : '').'</a>'. '<br /> (Message will be sent when you click on Save & Next below.)'."\n" if ($ENV{'form.handgrade'} eq 'yes'); $request->print($result); @@ -1022,26 +1107,45 @@ KEYWORDS '<option selected="on"> </option>'. '<option>excused</option></select>'."  \n"; $result.='<input type="hidden" name="stores'.$counter.'_'.$partid.'" value="0" />'; - $result.='</td></tr></table>'; + $result.='</td></tr></table>'."\n"; $request->print($result); } - $request->print('<input type="hidden" name="partlist'.$counter.'" value="'.(join ":",@partlist).'" />'."\n"); - $request->print('</td></tr></table></td></tr></table>'."\n"); + $result='<input type="hidden" name="partlist'.$counter. + '" value="'.(join ":",@partlist).'" />'."\n"; + my $ctr = 0; + while ($ctr < scalar(@partlist)) { + $result.='<input type="hidden" name="partid'.$counter.'_'.$ctr.'" value="'. + $partlist[$ctr].'" />'."\n"; + $ctr++; + } + $request->print($result.'</td></tr></table></td></tr></table>'."\n"); # print end of form if ($counter == $total) { - my $endform.='<table border="0"><tr><td><input type="submit" name="gradeOpt" value="Save & Next" />'; - my $ntstu ='<select name="NTSTU">'. - '<option>1</option><option>2</option>'. - '<option>3</option><option>5</option>'. - '<option>7</option><option>10</option></select>'."\n"; - my $nsel = ($ENV{'form.NTSTU'} ne '' ? $ENV{'form.NTSTU'} : '1'); - $ntstu =~ s/<option>$nsel</<option selected="on">$nsel</; - $endform.=$ntstu.'student(s) '. - '<input type="submit" name="gradeOpt" value="Next" /> '. - '<input type="submit" name="gradeOpt" value="Previous" /> '. - '(Next and Previous do not save the scores.)'. - '</td><tr></table></form>'; + my $endform='<table border="0"><tr><td>'. + '<input type="hidden" name="gradeOpt" value="" />'."\n"; + if ($ENV{'form.handgrade'} eq 'yes') { + $endform.='<input type="button" value="Save & Next" '. + 'onClick="javascript:checksubmit(\'Save & Next\','. + $total.','.scalar(@partlist).');" TARGET=_self> '."\n"; + my $ntstu ='<select name="NTSTU">'. + '<option>1</option><option>2</option>'. + '<option>3</option><option>5</option>'. + '<option>7</option><option>10</option></select>'."\n"; + my $nsel = ($ENV{'form.NTSTU'} ne '' ? $ENV{'form.NTSTU'} : '1'); + $ntstu =~ s/<option>$nsel</<option selected="on">$nsel</; + $endform.=$ntstu.'student(s) '; + } else { + $endform.='<input type="hidden" name="NTSTU" value="1" />'."\n"; + } + $endform.='<input type="button" value="Next" '. + 'onClick="javascript:checksubmit(\'Next\');" TARGET=_self> '."\n". + '<input type="button" value="Previous" '. + 'onClick="javascript:checksubmit(\'Previous\');" TARGET=_self> '; + $endform.='(Next and Previous do not save the scores.)'."\n" + if ($ENV{'form.handgrade'} eq 'yes'); + $endform.='</td><tr></table></form>'; + $endform.=&show_grading_menu_form($symb,$url); $request->print($endform); } return ''; @@ -1049,31 +1153,30 @@ KEYWORDS #--- Retrieve the last submission for all the parts sub get_last_submission { - my ($symb,$username,$domain,$course)=@_; - if ($symb) { - my (@string,$timestamp); - my (%returnhash)=&Apache::lonnet::restore($symb,$course,$domain,$username); - if ($returnhash{'version'}) { - my %lasthash=(); - my ($version); - for ($version=1;$version<=$returnhash{'version'};$version++) { - foreach (sort(split(/\:/,$returnhash{$version.':keys'}))) { - $lasthash{$_}=$returnhash{$version.':'.$_}; - } - } - foreach ((keys %lasthash)) { - if ($_ =~ /\.submission$/) { - my ($partid,$foo) = split(/submission$/,$_); - my $draft = $lasthash{$partid.'awarddetail'} eq 'DRAFT' ? - '<font color="red">Draft Copy</font> ' : ''; - push @string, (join(':',$_,$draft.$lasthash{$_})); - } - if ($_ =~ /timestamp/) {$timestamp = scalar(localtime($lasthash{$_}))}; + my (%returnhash)=@_; + my (@string,$timestamp); + if ($returnhash{'version'}) { + my %lasthash=(); + my ($version); + for ($version=1;$version<=$returnhash{'version'};$version++) { + foreach (sort(split(/\:/,$returnhash{$version.':keys'}))) { + $lasthash{$_}=$returnhash{$version.':'.$_}; + if ($returnhash{$version.':'.$_} =~ /(SUBMITTED|DRAFT)$/) { + $timestamp = scalar(localtime($returnhash{$version.':timestamp'})); + } + } + } + foreach ((keys %lasthash)) { + if ($_ =~ /\.submission$/) { + my ($partid,$foo) = split(/submission$/,$_); + my $draft = $lasthash{$partid.'awarddetail'} eq 'DRAFT' ? + '<font color="red">Draft Copy</font> ' : ''; + push @string, (join(':',$_,$draft.$lasthash{$_})); } } - @string = $string[0] eq '' ? 'Nothing submitted - no attempts.' : @string; - return \@string,\$timestamp; } + @string = $string[0] eq '' ? 'Nothing submitted - no attempts.' : @string; + return \@string,\$timestamp; } #--- High light keywords, with style choosen by user. @@ -1102,8 +1205,7 @@ sub processHandGrade { my $ctr = 0; while ($ctr < $ngrade) { my ($uname,$udom) = split(/:/,$ENV{'form.unamedom'.$ctr}); - my ($errorflg) = &saveHandGrade($request,$url,$symb,$uname,$udom,$ctr); - return '' if ($errorflg eq 'error'); + my ($errorflag) = &saveHandGrade($request,$url,$symb,$uname,$udom,$ctr); my $includemsg = $ENV{'form.includemsg'.$ctr}; my ($subject,$message,$msgstatus) = ('','',''); @@ -1198,7 +1300,7 @@ sub processHandGrade { my ($classlist,$seclist,$ids,$stusec,$fullname) = &getclasslist($ENV{'form.section'},'0'); my (@parsedlist,@nextlist); my ($nextflg) = 0; - foreach (sort {$$fullname{$a} cmp $$fullname{$b} } keys %$fullname) { + foreach (sort {lc($$fullname{$a}) cmp lc($$fullname{$b}) } keys %$fullname) { if ($nextflg == 1 && $button =~ /Next$/) { push @parsedlist,$_; } @@ -1263,11 +1365,6 @@ sub saveHandGrade { my $pts = ($ENV{'form.GD_BOX'.$newflg.'_'.$_} ne '' ? $ENV{'form.GD_BOX'.$newflg.'_'.$_} : $ENV{'form.RADVAL'.$newflg.'_'.$_}); - if ($pts eq '') { - &userError($request,'No point was assigned for part '.$_. - ' and for username '.$stuname.'.'); - return 'error'; - } my $wgt = $ENV{'form.WGT'.$newflg.'_'.$_} eq '' ? 1 : $ENV{'form.WGT'.$newflg.'_'.$_}; my $partial= $pts/$wgt; @@ -1304,13 +1401,7 @@ sub viewgrades_js { $request->print(<<VIEWJAVASCRIPT); <script type="text/javascript" language="javascript"> - function viewOneStudent(user,domain) { - document.onestudent.student.value = user; - document.onestudent.userdom.value = domain; - document.onestudent.submit(); - } - - function writePoint(partid,weight,point) { + function writePoint(partid,weight,point) { var radioButton = eval("document.classgrade.RADVAL_"+partid); var textbox = eval("document.classgrade.TEXTVAL_"+partid); if (point == "textval") { @@ -1480,18 +1571,12 @@ sub viewgrades { &viewgrades_js($request); my ($symb,$url) = ($ENV{'form.symb'},$ENV{'form.url'}); - my $result='<h2><font color="#339933">Manual Grading</font></h2>'; + my $result='<h3><font color="#339933">Manual Grading</font></h3>'; $result.='<font size=+1><b>Resource: </b>'.$ENV{'form.url'}.'</font>'."\n"; #view individual student submission form - called using Javascript viewOneStudent - $result.= '<form action="/adm/grades" method="post" name="onestudent">'."\n". - '<input type="hidden" name="symb" value="'.$symb.'" />'."\n". - '<input type="hidden" name="url" value="'.$url.'" />'."\n". - '<input type="hidden" name="command" value="submission" />'."\n". - '<input type="hidden" name="student" value="" />'."\n". - '<input type="hidden" name="userdom" value="" />'."\n". - '</form>'."\n"; + $result.=&jscriptNform($url,$symb); #beginning of class grading form $result.= '<form action="/adm/grades" method="post" name="classgrade">'."\n". @@ -1499,22 +1584,34 @@ sub viewgrades { '<input type="hidden" name="url" value="'.$url.'" />'."\n". '<input type="hidden" name="command" value="editgrades" />'."\n". '<input type="hidden" name="section" value="'.$ENV{'form.section'}.'" />'."\n"; - - $result.='To assign the same score for all the students use the radio buttons or '. - 'text box below. To assign scores individually fill in the score boxes for '. - 'each student in the table below. <font color="red">A part that has already '. - 'been graded does not get changed using the radio buttons or text box. '. - 'If needed, it has to be changed individually.</font>'; - + $result.='<h3>Assign Common Grade To '; + if ($ENV{'form.section'} eq 'all') { + $result.='Class </h3>'; + } elsif ($ENV{'form.section'} eq 'no') { + $result.='Students in no Section </h3>'; + } else { + $result.='Students in Section '.$ENV{'form.section'}.'</h3>'; + } + $result.= '<table border=0><tr><td bgcolor="#777777">'."\n". + '<table border=0><tr bgcolor="#ffffdd"><td>'; +# $result.='To assign the same score for all the students use the radio buttons or '. +# 'text box below. To assign scores individually fill in the score boxes for '. +# 'each student in the table below. <font color="red">A part that has already '. +# 'been graded does not get changed using the radio buttons or text box. '. +# 'If needed, it has to be changed individually.</font>'; +# $result.='</td></tr><tr><td>'; #radio buttons/text box for assigning points for a section or class. #handles different parts of a problem my ($partlist,$handgrade) = &response_type($ENV{'form.url'}); my %weight = (); my $ctsparts = 0; $result.='<table border="0">'; + my %seen = (); for (sort keys(%$handgrade)) { - my ($responsetype,$handgrade)=split(/:/,$$handgrade{$_}); my ($partid,$respid) = split (/_/); + next if $seen{$partid}; + $seen{$partid}++; + my ($responsetype,$handgrade)=split(/:/,$$handgrade{$_}); my $wgt = &Apache::lonnet::EXT('resource.'.$partid.'.weight',$symb); $weight{$partid} = $wgt eq '' ? '1' : $wgt; @@ -1544,15 +1641,23 @@ sub viewgrades { '<option>excused</option></select></td></tr>'."\n"; $ctsparts++; } - $result.='</table><input type="hidden" name="totalparts" value="'.$ctsparts.'" />'; + $result.='</table>'.'</td></tr></table>'.'</td></tr></table>'."\n". + '<input type="hidden" name="totalparts" value="'.$ctsparts.'" />'; $result.='<input type="button" value="Reset" '. 'onClick="javascript:resetEntry('.$ctsparts.');" TARGET=_self> '; -# $result.='<input type="button" value="Submit Changes" '. -# 'onClick="submit();" TARGET=_self />'."\n"; - $result.= '<input type="submit" name="submit" value="Submit Changes" />'."\n"; + $result.='<input type="button" value="Submit Changes" '. + 'onClick="javascript:submit();" TARGET=_self />'."\n"; #table listing all the students in a section/class #header of table + $result.= '<h3>Assign Grade to Specific Students in '; + if ($ENV{'form.section'} eq 'all') { + $result.='the Class </h3>'; + } elsif ($ENV{'form.section'} eq 'no') { + $result.='no Section </h3>'; + } else { + $result.='Section '.$ENV{'form.section'}.'</h3>'; + } $result.= '<table border=0><tr><td bgcolor="#777777">'."\n". '<table border=0><tr bgcolor="#deffff">'. '<td><b>Fullname</b></td><td><b>Username</b></td><td><b>Domain</b></td>'."\n"; @@ -1564,11 +1669,11 @@ sub viewgrades { if ($display =~ /^Partial Credit Factor/) { $_ = $display; my ($partid) = /.*?(\d+).*/; - $result.='<td><b>Score Part '.$partid.'<br>(weight = '. + $result.='<td><b>Score Part '.$partid.'<br />(weight = '. $weight{$partid}.')</b></td>'."\n"; next; } - $display =~ s/Problem Status/Grade Status<br>/; + $display =~ s|Problem Status|Grade Status<br />|; $result.='<td><b>'.$display.'</b></td>'."\n"; } $result.='</tr>'; @@ -1577,7 +1682,7 @@ sub viewgrades { #list all the students - with points and grade status my ($classlist,$seclist,$ids,$stusec,$fullname) = &getclasslist($ENV{'form.section'},'0'); my $ctr = 0; - foreach (sort {$$fullname{$a} cmp $$fullname{$b} } keys %$fullname) { + foreach (sort {lc($$fullname{$a}) cmp lc($$fullname{$b}) } keys %$fullname) { my ($uname,$udom) = split(/:/); $result.='<input type="hidden" name="ctr'.$ctr.'" value="'.$uname.'" />'."\n"; $result.=&viewstudentgrade($url,$symb,$ENV{'request.course.id'}, @@ -1586,7 +1691,8 @@ sub viewgrades { } $result.='</table></td></tr></table>'; $result.='<input type="hidden" name="total" value="'.$ctr.'" />'."\n"; - $result.='<input type="submit" name="submit" value="Submit Changes" /></form>'; + $result.='<input type="button" value="Submit Changes" '. + 'onClick="javascript:submit();" TARGET=_self /></form>'."\n"; $result.=&show_grading_menu_form($symb,$url); return $result; } @@ -1638,7 +1744,7 @@ sub editgrades { my $symb=$ENV{'form.symb'}; my $url =$ENV{'form.url'}; - my $title='<h2><font color="#339933">Current Grade Status</font></h2>'; + my $title='<h3><font color="#339933">Current Grade Status</font></h3>'; $title.='<font size=+1><b>Resource: </b>'.$ENV{'form.url'}.'</font><br />'."\n"; $title.='<font size=+1><b>Section: </b>'.$ENV{'form.section'}.'</font>'."\n"; $title.= &show_grading_menu_form ($symb,$url); @@ -1810,16 +1916,30 @@ ENDPICK sub csvuploadmap_header { my ($request,$symb,$url,$datatoken,$distotal)= @_; - my $result; my $javascript; if ($ENV{'form.upfile_associate'} eq 'reverse') { $javascript=&csvupload_javascript_reverse_associate(); } else { $javascript=&csvupload_javascript_forward_associate(); } + + my $result='<table border="0">'; + $result.='<tr><td colspan=3><font size=+1><b>Resource: </b>'.$url.'</font></td></tr>'; + my ($partlist,$handgrade) = &response_type($url); + my ($resptype,$hdgrade)=('','no'); + for (sort keys(%$handgrade)) { + my ($responsetype,$handgrade)=split(/:/,$$handgrade{$_}); + $resptype = $responsetype; + $hdgrade = $handgrade if ($handgrade eq 'yes'); + $result.='<tr><td><b>Part </b>'.(split(/_/))[0].'</td>'. + '<td><b>Type: </b>'.$responsetype.'</td>'. + '<td><b>Handgrade: </b>'.$handgrade.'</font></td></tr>'; + } + $result.='</table>'; $request->print(<<ENDPICK); <form method="post" enctype="multipart/form-data" action="/adm/grades" name="gradesupload"> -<h3>Uploading Class Grades for resource $url</h3> +<h3><font color="#339933">Uploading Class Grades</font></h3> +$result <hr> <h3>Identify fields</h3> Total number of records found in file: $distotal <hr /> @@ -1887,6 +2007,7 @@ sub csvuploadmap { my ($i,$keyfields); if (@records) { my @fields=&csvupload_fields($url); + if ($ENV{'form.upfile_associate'} eq 'reverse') { &Apache::loncommon::csv_print_samples($request,\@records); $i=&Apache::loncommon::csv_print_select_table($request,\@records, @@ -1926,8 +2047,6 @@ sub csvuploadassign { } $request->print('<h3>Assigning Grades</h3>'); my $courseid=$ENV{'request.course.id'}; -# my $cdom=$ENV{"course.$courseid.domain"}; -# my $cnum=$ENV{"course.$courseid.num"}; my ($classlist) = &getclasslist('all','1'); my @skipped; my $countdone=0; @@ -1987,7 +2106,7 @@ sub gradingmenu { my ($request) = @_; my ($symb,$url)=&get_symb_and_url($request); if (!$symb) {return '';} - my $result='<h2> <font color="#339933">Select a Grading Method</font></h2>'; + my $result='<h3> <font color="#339933">Select a Grading Method</font></h3>'; $result.='<table border="0">'; $result.='<tr><td colspan=3><font size=+1><b>Resource: </b>'.$url.'</font></td></tr>'; my ($partlist,$handgrade) = &response_type($url); @@ -2016,18 +2135,20 @@ sub view_edit_entire_class_form { my ($classlist,$sections) = &getclasslist('all','0'); my $result.='<table width=100% border=0><tr><td bgcolor=#777777>'."\n"; $result.='<table width=100% border=0><tr bgcolor="#e6ffff"><td>'."\n"; - $result.=' <b>View/Grade Entire Section/Class</b></td></tr>'."\n"; + $result.=' <b>Grade Entire Section or Class</b></td></tr>'."\n"; $result.='<tr bgcolor=#ffffe6><td>'."\n"; $result.='<form action="/adm/grades" method="post">'."\n". '<input type="hidden" name="symb" value="'.$symb.'" />'."\n". '<input type="hidden" name="url" value="'.$url.'" />'."\n". '<input type="hidden" name="command" value="viewgrades" />'."\n"; $result.=' <b>Select section:</b> <select name="section">'."\n"; - foreach (sort (@$sections)) { - $result.= '<option>'.$_.'</option>'."\n"; + if (ref($sections)) { + foreach (sort (@$sections)) { + $result.= '<option>'.$_.'</option>'."\n"; + } } $result.='<option selected="on">all</select>'."<br />\n"; - $result.=' <input type="submit" name="submit" value="View/Grade" /></form>'."\n"; + $result.=' <input type="button" onClick="submit();" value="Grade" /></form>'."\n"; $result.='</td></tr></table>'."\n"; $result.='</td></tr></table>'."\n"; return $result; @@ -2037,7 +2158,17 @@ sub view_edit_entire_class_form { sub upcsvScores_form { my ($symb,$url) = @_; if (!$symb) {return '';} - my $result.='<table width=100% border=0><tr><td bgcolor=#777777>'."\n"; + my $result = '<script type="text/javascript" language="javascript">'."\n". + ' function checkUpload(formname) {'."\n". + ' if (formname.upfile.value == "") {'."\n". + ' alert("Please use the browse button to select a file from your local directory.");'."\n". + ' return false;'."\n". + ' }'."\n". + ' formname.submit();'."\n". + ' }'."\n". + '</script>'."\n"; + + $result.='<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 above resource</b></td></tr>'."\n"; $result.='<tr bgcolor=#ffffe6><td>'."\n"; @@ -2048,7 +2179,7 @@ sub upcsvScores_form { <input type="hidden" name="url" value="$url" /> <input type="hidden" name="command" value="csvuploadmap" /> $upfile_select -<br /> <input type="submit" name="submit" value="Upload Grades" /> +<br /> <input type="button" onClick="javascript:checkUpload(this.form);" value="Upload Grades" /> </form> ENDUPFORM $result.='</td></tr></table>'."\n"; @@ -2062,7 +2193,13 @@ sub viewGradeaStu_form { my ($classlist,$sections) = &getclasslist('all','0'); my $result.='<table width=100% border=0><tr><td bgcolor=#777777>'."\n"; $result.='<table width=100% border=0><tr bgcolor="#e6ffff"><td>'."\n"; - $result.=' <b>View/Grade an Individual Student\'s Submission</b></td></tr>'."\n"; + $result.=' <b>'; + if ($handgrade eq 'yes') { + $result.="View/Grade "; + } else { + $result.="View "; + } + $result.='an Individual Student\'s Submission</b></td></tr>'."\n"; $result.='<tr bgcolor=#ffffe6><td>'."\n"; $result.='<form action="/adm/grades" method="post">'."\n". '<input type="hidden" name="symb" value="'.$symb.'" />'."\n". @@ -2073,18 +2210,26 @@ sub viewGradeaStu_form { '<input type="hidden" name="command" value="submission" />'."\n"; $result.=' <b>Select section:</b> <select name="section">'."\n"; - foreach (sort (@$sections)) { - $result.= '<option>'.$_.'</option>'."\n"; + if (ref($sections)) { + foreach (sort (@$sections)) {$result.='<option>'.$_.'</option>'."\n";} } $result.= '<option selected="on">all</select>'."\n"; $result.=' <b>Display students who has: </b>'. '<input type="radio" name="submitonly" value="yes" checked> submitted'. '<input type="radio" name="submitonly" value="all"> everybody <br />'; - $result.=' (Section "no" implies the students were not assigned a section.)<br />' - if (grep /no/,@$sections); - - $result.='<br /> <input type="submit" name="submit" value="View/Grade" />'."\n". - '</form>'."\n"; + if (ref($sections)) { + $result.=' (Section "no" implies the students were not assigned a section.)<br />' + if (grep /no/,@$sections); + } + + + $result.='<br /> <input type="button" onClick="submit();" value="'; + if ($handgrade eq 'yes') { + $result.="View/Grade"; + } else { + $result.="View"; + } + $result.='" />'."\n".'</form>'."\n"; $result.='</td></tr></table>'."\n"; $result.='</td></tr></table>'."\n"; return $result; @@ -2093,17 +2238,27 @@ sub viewGradeaStu_form { #--- Form to input a receipt number --- sub verifyReceipt_form { my ($symb,$url) = @_; - my $cdom=$ENV{"course.$ENV{'request.course.id'}.domain"}; - my $cnum=$ENV{"course.$ENV{'request.course.id'}.num"}; + my $result = '<script type="text/javascript" language="javascript">'."\n". + ' function checkEntry(formname) {'."\n". + ' var receipt = formname.receipt.value;'."\n". + ' if (isNaN(receipt) || receipt == "") {'."\n". + ' alert("Please enter a receipt number given by a student in the box.");'."\n". + ' return false;'."\n". + ' }'."\n". + ' formname.submit();'."\n". + ' }'."\n". + '</script>'."\n"; + my $hostver=unpack("%32C*",$Apache::lonnet::perlvar{'lonHostID'}); - my $result.='<table width=100% border=0><tr><td bgcolor=#777777>'."\n"; + $result.='<table width=100% border=0><tr><td bgcolor=#777777>'."\n"; $result.='<table width=100% border=0><tr><td bgcolor=#e6ffff>'."\n"; $result.=' <b>Verify a Submission Receipt Issued by this Server</td></tr>'."\n"; $result.='<tr bgcolor=#ffffe6><td>'."\n"; - $result.='<form action="/adm/grades" method="post">'."\n"; + $result.='<form action="/adm/grades" method="post" name="verifyform">'."\n"; $result.=' <tt>'.$hostver.'-<input type="text" name="receipt" size="4"></tt><br />'."\n"; - $result.=' <input type="submit" name="submit" value="Verify Receipt">'."\n"; + $result.=' <input type="button" onClick="javascript:checkEntry(this.form);"'. + ' value="Verify Receipt">'."\n"; $result.='<input type="hidden" name="command" value="verify">'."\n"; if ($ENV{'form.url'}) { $result.='<input type="hidden" name="url" value="'.$ENV{'form.url'}.'" />'; @@ -2155,17 +2310,16 @@ sub handler { 'grade_courseid' => $tcrsid, 'grade_symb' => $tsymb))); } else { - $request->print('<h2>Not authorized: '.$token.'</h2>'); + $request->print('<h3>Not authorized: '.$token.'</h3>'); } } else { - $request->print('<h2>Not a valid DocID: '.$token.'</h2>'); + $request->print('<h3>Not a valid DocID: '.$token.'</h3>'); } } else { $request->print(&Apache::lonxml::tokeninputfield()); } } } else { - #&Apache::lonhomework::showhashsubset(\%ENV,'^form'); $Apache::grades::viewgrades=&Apache::lonnet::allowed('vgr',$ENV{'request.course.id'}); if ($command eq 'submission') { &listStudents($request) if ($ENV{'form.student'} eq ''); @@ -2215,7 +2369,7 @@ sub send_header { #remotewindow=open('','homeworkremote'); #remotewindow.close(); #</script>"); - $request->print('<body bgcolor="#FFFFFF">'); + $request->print(&Apache::loncommon::bodytag('Grading')); } sub send_footer {