[LON-CAPA-cvs] cvs: loncom /homework grades.pm

ng lon-capa-cvs@mail.lon-capa.org
Mon, 05 Aug 2002 20:49:54 -0000


This is a MIME encoded message

--ng1028580594
Content-Type: text/plain

ng		Mon Aug  5 16:49:54 2002 EDT

  Modified files:              
    /loncom/homework	grades.pm 
  Log:
  move error checking using javascript instead of grades.pm
  
  Error: From view/grade page - prompt if not student is selected
  Error: From grading page - prompt if no score is selected when clicking on
  	Save & Next.
  
  A few other display changes.
  
  
  
--ng1028580594
Content-Type: text/plain
Content-Disposition: attachment; filename="ng-20020805164954.txt"

Index: loncom/homework/grades.pm
diff -u loncom/homework/grades.pm:1.44 loncom/homework/grades.pm:1.45
--- loncom/homework/grades.pm:1.44	Fri Aug  2 17:10:03 2002
+++ loncom/homework/grades.pm	Mon Aug  5 16:49:54 2002
@@ -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.45 2002/08/05 20:49:54 ng Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -45,6 +45,17 @@
 
 # ----- These first few routines are general use routines.-----
 #
+
+sub print_hash {
+    my ($request, $hash) = @_;
+    $request->print('<table border=1><tr><td>Key</td><td>Value</td></tr>');
+    for (sort keys (%$hash)) {
+	$request->print('<tr><td>'.$_.'</td><td>'.$$hash{$_}.'&nbsp;</td></tr>');
+    }
+    $request->print('</table>');
+    return '';
+}
+
 # --- Retrieve the parts that matches stores_\d+ from the metadata file.---
 sub getpartlist {
     my ($url) = @_;
@@ -224,11 +235,33 @@
     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,23 +276,8 @@
 	$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);
@@ -281,7 +299,7 @@
     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".
@@ -301,13 +319,37 @@
 #    on the problem page.
 sub listStudents {
     my ($request) = shift;
+    $request->print(<<LISTJAVASCRIPT);
+<script type="text/javascript" language="javascript">
+  function checkSelect(checkBox) {
+    var ctr=0;
+    if (checkBox.length > 1) {
+       for (var i=0; i<checkBox.length; i++) {
+	  if (checkBox[i].checked) {
+	     ctr++;
+	  }
+       }
+    } else {
+       if (checkBox.checked) {
+	   ctr = 1;
+       }
+    }
+    if (ctr == 0) {
+       alert("You did not select any student.");
+       return false;
+    }
+    document.gradesub.submit();
+  }
+</script>
+LISTJAVASCRIPT
+
     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">&nbsp;'.
-	'View Submissions for a Student or a Group of Students</font></h2>';
+    my $result='<h3><font color="#339933">&nbsp;'.
+	'View/Grade Submissions for a Student or a Group of Students</font></h3>';
     $result.='<table border="0">';
     $result.='<tr><td colspan=3><font size=+1>'.
 	'<b>Resource: </b>'.$ENV{'form.url'}.'</font></td></tr>';
@@ -322,41 +364,44 @@
     $result.='</table>';
     $request->print($result);
 
-    $request->print(<<ENDTABLEST);
-<form action="/adm/grades" method="post">
-&nbsp;<b>View Problem: </b><input type="radio" name="vProb" value="no" checked> no 
-<input type="radio" name="vProb" value="yes"> yes <br />
-&nbsp;<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");
-    }
-    if ($ENV{'form.symb'}) {
-	$request->print('<input type="hidden" name="symb" value="'.$ENV{'form.symb'}.'" />'."\n");
-    }
-    $request->print('<input type="hidden" name="command" value="processGroup" />'."\n");
+    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".
+	'&nbsp;<b>View Problem: </b><input type="radio" name="vProb" value="no" checked> no '."\n".
+	'<input type="radio" name="vProb" value="yes"> yes <br />'."\n".
+	'&nbsp;<b>Submissions: </b>'."\n".
+	'<input type="radio" name="lastSub" value="hdgrade" '.$checkhdgrade.' /> handgrade only'."\n".
+	'<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="'.$ENV{'form.url'}.'" />'."\n".
+	'<input type="hidden" name="symb" value="'.$ENV{'form.symb'}.'" />'."\n".
+	'To view/grade a submission, click on the check box next to the student\'s name. Then '."\n".
+	'click on the View/Grade 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="View/Grade" />'."\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>&nbsp;Select&nbsp;</b></td><td><b>&nbsp;Fullname&nbsp;</b></td>'.
 	'<td><b>&nbsp;Username&nbsp;</b></td><td><b>&nbsp;Domain&nbsp;</b></td>';
     foreach (sort(@$partlist)) {
-	$result.='<td><b>&nbsp;Part '.(split(/_/))[0].' Status&nbsp;</b></td>';
+	$gradeTable.='<td><b>&nbsp;Part '.(split(/_/))[0].' Status&nbsp;</b></td>';
     }
-    $request->print($result.'</tr>'."\n");
+    $gradeTable.='</tr>'."\n";
 
+    my $ctr = 0;
     foreach my $student (sort {$$fullname{$a} cmp $$fullname{$b} } keys %$fullname) {
 	my ($uname,$udom) = split(/:/,$student);
 	my (%status) = &student_gradeStatus($ENV{'form.url'},
@@ -367,15 +412,16 @@
 	    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>&nbsp;'.$$fullname{$student}.'&nbsp;</td>'."\n".
@@ -384,13 +430,21 @@
 	    
 	    foreach (sort keys(%status)) {
 		next if (/^resource.*?submitted_by$/);
-		$result.='<td align="middle">&nbsp;'.$status{$_}.'&nbsp;</td>'."\n";
+		$gradeTable.='<td align="middle">&nbsp;'.$status{$_}.'&nbsp;</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="View/Grade" /><form />'."\n";
+    if ($ctr == 0) {
+	$gradeTable='<br />&nbsp;<font color="red">'.
+	    'No submission found for this resource.</font><br />';
+	$gradeTable.=&show_grading_menu_form ($ENV{'form.symb'},$ENV{'form.url'});
+    }
+    $request->print($gradeTable);
     return '';
 }
 
@@ -402,10 +456,7 @@
     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 @@
     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("You did not assign any point for "+name+", part "+partid+".");
+		     return false;
+		 }
+	      }
+
+	  }
+       }
+
+     }
+     document.SCORE.submit();
+ }
+
 //===================== Show list of keywords ====================
   function keywords(keyform) {
     var keywds = keyform.value;
@@ -766,8 +841,8 @@
     # header info
     if ($counter == 0) {
 	&sub_page_js($request);
-	$request->print('<h2>&nbsp;<font color="#339933">Submission Record</font></h2>'.
-			'<font size=+1>&nbsp;<b>Resource: </b>'.$url.'</font>');
+	$request->print('<h3>&nbsp;<font color="#339933">Submission Record</font></h3>'."\n".
+			'<font size=+1>&nbsp;<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 @@
 								   $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,18 @@
 
     # 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">&nbsp; &nbsp;Username: '.$uname.'</font>'.
-	'<font color="#999999">&nbsp; &nbsp;Domain: '.$udom.'</font><br />';
+	'<font color="#999999">&nbsp; &nbsp;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 +960,9 @@
 				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}.'&nbsp; &nbsp; &nbsp;';
 			}
 			$result.='<br />'."\n";
@@ -929,7 +1007,7 @@
 		($$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 +1017,7 @@
 			    $lastsubonly.='<tr><td bgcolor="#ffffe6"><b>Part '.
 				$partid.'</b> <font color="#999999">( ID '.$respid.
 				' )</font>&nbsp; &nbsp;<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 +1025,7 @@
 		    }
 		}
 	    }
-	    $lastsubonly.='</td></tr><tr><td bgcolor="#ffffff">'."\n";
+	    $lastsubonly.='</td></tr>'."\n";
 	    $request->print($lastsubonly);
 	}
     } else {
@@ -959,17 +1037,25 @@
     
     # 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.='&nbsp;<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".
+	'&nbsp;<a href="javascript:msgCenter(document.SCORE,'.$counter.
+	',\''.$msgfor.'\')"; TARGET=_self>'.
+	'Compose Message to student'.(scalar(@col_fullnames) >= 1 ? 's' : '').'</a>'.
 	'<br />&nbsp;(Message will be sent when you click on Save & Next below.)'."\n" 
 	if ($ENV{'form.handgrade'} eq 'yes');
     $request->print($result);
@@ -1022,26 +1108,44 @@
 	    '<option selected="on"> </option>'.
 	    '<option>excused</option></select>'."&nbsp&nbsp\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) &nbsp;&nbsp;'.
-	    '<input type="submit" name="gradeOpt" value="Next" />&nbsp'.
-	    '<input type="submit" name="gradeOpt" value="Previous" />&nbsp'.
-	    '(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> &nbsp;'."\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) &nbsp;&nbsp;';
+	} else {
+	    $endform.='<input type="hidden" name="NTSTU" value="1" />'."\n";
+	}
+	$endform.='<input type="button" value="Next" '.
+	    'onClick="javascript:checksubmit(\'Next\');" TARGET=_self> &nbsp;'."\n".
+	    '<input type="button" value="Previous" '.
+	    'onClick="javascript:checksubmit(\'Previous\');" TARGET=_self> &nbsp;';
+	$endform.='(Next and Previous do not save the scores.)'."\n" 
+	    if ($ENV{'form.handgrade'} eq 'yes');
+	$endform.='</td><tr></table></form>';
 	$request->print($endform);
     }
     return '';
@@ -1102,8 +1206,7 @@
 	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) = ('','','');
@@ -1263,11 +1366,6 @@
 	    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 +1402,7 @@
 
     $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 +1572,12 @@
     &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,7 +1585,6 @@
 	'<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 '.
@@ -1512,9 +1597,12 @@
     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;
 
@@ -1547,9 +1635,8 @@
     $result.='</table><input type="hidden" name="totalparts" value="'.$ctsparts.'" />';
     $result.='<input type="button" value="Reset" '.
 	'onClick="javascript:resetEntry('.$ctsparts.');" TARGET=_self> &nbsp; &nbsp;';
-#    $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
@@ -1586,7 +1673,8 @@
     }
     $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 +1726,7 @@
 
     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 +1898,30 @@
 
 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 +1989,7 @@
     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,
@@ -1987,7 +2090,7 @@
     my ($request) = @_;
     my ($symb,$url)=&get_symb_and_url($request);
     if (!$symb) {return '';}
-    my $result='<h2>&nbsp;<font color="#339933">Select a Grading Method</font></h2>';
+    my $result='<h3>&nbsp;<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);
@@ -2155,10 +2258,10 @@
 							      '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());

--ng1028580594--