--- loncom/homework/grades.pm	2002/08/05 20:49:54	1.45
+++ loncom/homework/grades.pm	2002/10/04 06:22:12	1.54
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # The LON-CAPA Grading handler
 #
-# $Id: grades.pm,v 1.45 2002/08/05 20:49:54 ng Exp $
+# $Id: grades.pm,v 1.54 2002/10/04 06:22:12 albertel Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -45,24 +45,13 @@ use Apache::Constants qw(:common);
 
 # ----- 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) = @_;
     my @parts =();
     my (@metakeys) = split(/,/,&Apache::lonnet::metadata($url,'keys'));
     foreach my $key (@metakeys) {
-	if ( $key =~ m/stores_([0-9]+)_.*/) {
+	if ( $key =~ m/stores_(\w+)_.*/) {
 	    push(@parts,$key);
 	}
     }
@@ -102,7 +91,7 @@ sub response_type {
     my %seen = ();
     my (@partlist,%handgrade);
     foreach (split(/,/,&Apache::lonnet::metadata($url,'packages'))) {
-	if (/^\w+response_\d+.*/) {
+	if (/^\w+response_\w+.*/) {
 	    my ($responsetype,$part) = split(/_/,$_,2);
 	    my ($partid,$respid) = split(/_/,$part);
 	    $handgrade{$part} = $responsetype.':'.($allkeys =~ /parameter_$part\_handgrade/ ? 'yes' : 'no');
@@ -114,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 {
@@ -133,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) {
@@ -283,7 +265,7 @@ sub verifyreceipt {
     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)) {
@@ -310,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.
@@ -319,23 +301,57 @@ 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;
+    my ($partlist,$handgrade) = &response_type($url);
+    for (sort keys(%$handgrade)) {
+	my ($responsetype,$handgrade)=split(/:/,$$handgrade{$_});
+	$ENV{'form.handgrade'} = 'yes' 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>';
+
+    my $viewgrade;
+    if ($ENV{'form.handgrade'} eq 'yes') {
+	$viewgrade = 'View/Grade';
+    } else {
+	$viewgrade = 'View';
+    }
+
+    $result='<h3><font color="#339933">&nbsp;'.
+	$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";
     }
     if (ctr == 0) {
-       alert("You did not select any student.");
+       alert("Please select "+sense+" before clicking on the $viewgrade button.");
        return false;
     }
     document.gradesub.submit();
@@ -343,25 +359,6 @@ sub listStudents {
 </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='<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>';
-    my ($partlist,$handgrade) = &response_type($ENV{'form.url'});
-    for (sort keys(%$handgrade)) {
-	my ($responsetype,$handgrade)=split(/:/,$$handgrade{$_});
-	$ENV{'form.handgrade'} = 'yes' 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($result);
 
     my $checkhdgrade = $ENV{'form.handgrade'} eq 'yes' ? 'checked' : '';
@@ -370,9 +367,11 @@ LISTJAVASCRIPT
     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".
+	'&nbsp;<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".
@@ -380,15 +379,15 @@ LISTJAVASCRIPT
 	'<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".
+	'<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="View/Grade" />'."\n";
+	'value="'.$viewgrade.'" />'."\n";
  
     my ($classlist,$seclist,$ids,$stusec,$fullname) = &getclasslist($getsec,'0');
     
@@ -402,10 +401,9 @@ LISTJAVASCRIPT
     $gradeTable.='</tr>'."\n";
 
     my $ctr = 0;
-    foreach my $student (sort {$$fullname{$a} cmp $$fullname{$b} } keys %$fullname) {
+    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');
@@ -438,12 +436,14 @@ LISTJAVASCRIPT
     $gradeTable.='</table></td></tr></table>'.
 	'<input type="button" '.
 	'onClick="javascript:checkSelect(this.form.stuinfo);" '.
-	'value="View/Grade" /><form />'."\n";
+	'value="'.$viewgrade.'" /></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'});
+    } elsif ($ctr == 1) {
+	$gradeTable =~ s/type=checkbox/type=checkbox checked/;
     }
+    $gradeTable.=&show_grading_menu_form($symb,$url);
     $request->print($gradeTable);
     return '';
 }
@@ -552,7 +552,7 @@ sub sub_page_js {
 		 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+".");
+		     alert("Please assign a score for "+name+", part "+partid+".");
 		     return false;
 		 }
 	      }
@@ -594,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);
@@ -929,7 +929,6 @@ KEYWORDS
     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 />'."\n";
@@ -1002,7 +1001,7 @@ 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).'';
@@ -1146,6 +1145,7 @@ KEYWORDS
 	$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 '';
@@ -1153,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.
@@ -1301,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,$_;
 	}
@@ -1442,10 +1441,10 @@ sub viewgrades_js {
 	for (i=0;i<document.classgrade.total.value;i++) {
 	    var user = eval("document.classgrade.ctr"+i+".value");
 	    var scorename = eval("document.classgrade.GD_"+user+
-				 "_"+partid+"_aw");
+				 "_"+partid+"_awarded");
 	    var saveval   = eval("document.classgrade.GD_"+user+
-				 "_"+partid+"_sv_s.value");
-	    var selname   = eval("document.classgrade.GD_"+user+"_"+partid+"_sv");
+				 "_"+partid+"_solved_s.value");
+	    var selname   = eval("document.classgrade.GD_"+user+"_"+partid+"_solved");
 	    if (saveval != "correct") {
 		scorename.value = point;
 		if (selname[0].selected != true) {
@@ -1471,11 +1470,11 @@ sub viewgrades_js {
 	    for (i=0;i<document.classgrade.total.value;i++) {
 		var user = eval("document.classgrade.ctr"+i+".value");
 		var scorename = eval("document.classgrade.GD_"+user+
-				     "_"+partid+"_aw");
+				     "_"+partid+"_awarded");
 		var saveval   = eval("document.classgrade.GD_"+user+
-				     "_"+partid+"_sv_s.value");
+				     "_"+partid+"_solved_s.value");
 		var selname   = eval("document.classgrade.GD_"+user+
-				     "_"+partid+"_sv");
+				     "_"+partid+"_solved");
 		if (saveval != "correct") {
 		    scorename.value = "";
 		    selname[1].selected = true;
@@ -1485,14 +1484,14 @@ sub viewgrades_js {
 	    for (i=0;i<document.classgrade.total.value;i++) {
 		var user = eval("document.classgrade.ctr"+i+".value");
 		var scorename = eval("document.classgrade.GD_"+user+
-				     "_"+partid+"_aw");
+				     "_"+partid+"_awarded");
 		var saveval   = eval("document.classgrade.GD_"+user+
-				     "_"+partid+"_sv_s.value");
+				     "_"+partid+"_solved_s.value");
 		var selname   = eval("document.classgrade.GD_"+user+
-				     "_"+partid+"_sv");
+				     "_"+partid+"_solved");
 		if (saveval != "correct") {
 		    scorename.value = eval("document.classgrade.GD_"+user+
-				     "_"+partid+"_aw_s.value");;
+				     "_"+partid+"_awarded_s.value");;
 		    selname[0].selected = true;
 		}
 	    }
@@ -1500,8 +1499,8 @@ sub viewgrades_js {
     }
 
     function changeSelect(partid,user) {
-	var selval = eval("document.classgrade.GD_"+user+'_'+partid+"_sv");
-	var textbox = eval("document.classgrade.GD_"+user+'_'+partid+"_aw");
+	var selval = eval("document.classgrade.GD_"+user+'_'+partid+"_solved");
+	var textbox = eval("document.classgrade.GD_"+user+'_'+partid+"_awarded");
 	var point  = textbox.value;
 	var weight = eval("document.classgrade.weight_"+partid+".value");
 
@@ -1522,9 +1521,9 @@ sub viewgrades_js {
     }
 
     function changeOneScore(partid,user) {
-	var selval = eval("document.classgrade.GD_"+user+'_'+partid+"_sv");
+	var selval = eval("document.classgrade.GD_"+user+'_'+partid+"_solved");
 	if (selval[1].selected) {
-	    var boxval = eval("document.classgrade.GD_"+user+'_'+partid+"_aw");
+	    var boxval = eval("document.classgrade.GD_"+user+'_'+partid+"_awarded");
 	    boxval.value = "";
 	}
     }
@@ -1545,14 +1544,14 @@ sub viewgrades_js {
 	    for (i=0;i<document.classgrade.total.value;i++) {
 		var user = eval("document.classgrade.ctr"+i+".value");
 		var resetscore = eval("document.classgrade.GD_"+user+
-				      "_"+partid+"_aw");
+				      "_"+partid+"_awarded");
 		resetscore.value = eval("document.classgrade.GD_"+user+
-					"_"+partid+"_aw_s.value");
+					"_"+partid+"_awarded_s.value");
 
 		var saveselval   = eval("document.classgrade.GD_"+user+
-				     "_"+partid+"_sv_s.value");
+				     "_"+partid+"_solved_s.value");
 
-		var selname   = eval("document.classgrade.GD_"+user+"_"+partid+"_sv");
+		var selname   = eval("document.classgrade.GD_"+user+"_"+partid+"_solved");
 		if (saveselval == "excused") {
 		    if (selname[1].selected == false) { selname[1].selected = true;}
 		} else {
@@ -1585,12 +1584,22 @@ 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'});
@@ -1599,7 +1608,7 @@ sub viewgrades {
     $result.='<table border="0">';
     my %seen = ();
     for (sort keys(%$handgrade)) {
-	my ($partid,$respid) = split (/_/);
+	my ($partid,$respid) = split (/_/,$_,2);
 	next if $seen{$partid};
 	$seen{$partid}++;
 	my ($responsetype,$handgrade)=split(/:/,$$handgrade{$_});
@@ -1615,24 +1624,25 @@ sub viewgrades {
 	my $ctr = 0;
 	while ($ctr<=$weight{$partid}) { # display radio buttons in a nice table 10 across
 	    $result.= '<td><input type="radio" name="RADVAL_'.$partid.'" '.
-		'onclick="javascript:writePoint('.$partid.','.$weight{$partid}.
+		'onclick="javascript:writePoint(\''.$partid.'\','.$weight{$partid}.
 		','.$ctr.')" />'.$ctr."</td>\n";
 	    $result.=(($ctr+1)%10 == 0 ? '</tr><tr>' : '');
 	    $ctr++;
 	}
 	$result.='</tr></table>';
 	$result.= '</td><td><b> or </b><input type="text" name="TEXTVAL_'.
-	    $partid.'" size="4" '.
-	    'onChange="javascript:writePoint('.$partid.','.$weight{$partid}.
-	    ',\'textval\')" /> /'.
+	    $partid.'" size="4" '.'onChange="javascript:writePoint(\''.
+		$partid.'\','.$weight{$partid}.',\'textval\')" /> /'.
 	    $weight{$partid}.' (problem weight)</td>'."\n";
 	$result.= '</td><td><select name="SELVAL_'.$partid.'"'.
-	    'onChange="javascript:writeRadText('.$partid.','.$weight{$partid}.')" /> '.
+	    'onChange="javascript:writeRadText(\''.$partid.'\','.
+		$weight{$partid}.')" /> '.
 	    '<option selected="on"> </option>'.
 	    '<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> &nbsp; &nbsp;';
     $result.='<input type="button" value="Submit Changes" '.
@@ -1640,22 +1650,28 @@ sub viewgrades {
 
     #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";
     my (@parts) = sort(&getpartlist($url));
     foreach my $part (@parts) {
 	my $display=&Apache::lonnet::metadata($url,$part.'.display');
-	next if ($display =~ /^Number of Attempts/);
 	if  (!$display) { $display = &Apache::lonnet::metadata($url,$part.'.name'); }
 	if ($display =~ /^Partial Credit Factor/) {
-	    $_ = $display;
-	    my ($partid) = /.*?(\d+).*/;
-	    $result.='<td><b>Score Part '.$partid.'<br>(weight = '.
+	    my ($partid) = &split_part_type($part);
+	    $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>';
@@ -1664,7 +1680,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'},
@@ -1689,30 +1705,36 @@ sub viewstudentgrade {
 	'\')"; TARGET=_self>'.$fullname.'</a>'.
 	'</td><td>'.$uname.'</td><td align="middle">'.$udom.'</td>'."\n";
     foreach my $part (@$parts) {
-	my ($temp,$part,$type)=split(/_/,$part);
+	my ($part,$type) = &split_part_type($part);
 	my $score=$record{"resource.$part.$type"};
-	next if $type eq 'tries';
 	if ($type eq 'awarded') {
 	    my $pts = $score eq '' ? '' : $score*$$weight{$part};
 	    $result.='<input type="hidden" name="'.
-		'GD_'.$uname.'_'.$part.'_aw_s" value="'.$pts.'" />'."\n";
+		'GD_'.$uname.'_'.$part.'_awarded_s" value="'.$pts.'" />'."\n";
 	    $result.='<td align="middle"><input type="text" name="'.
-		'GD_'.$uname.'_'.$part.'_aw" '.
-		'onChange="javascript:changeSelect('.$part.',\''.$uname.
+		'GD_'.$uname.'_'.$part.'_awarded" '.
+		'onChange="javascript:changeSelect(\''.$part.'\',\''.$uname.
 		'\')" value="'.$pts.'" size="4" /></td>'."\n";
 	} elsif ($type eq 'solved') {
 	    my ($status,$foo)=split(/_/,$score,2);
 	    $status = 'nothing' if ($status eq '');
-	    $result.='<input type="hidden" name="'.
-		'GD_'.$uname.'_'.$part.'_sv_s" value="'.$status.'" />'."\n";
+	    $result.='<input type="hidden" name="'.'GD_'.$uname.'_'.
+		$part.'_solved_s" value="'.$status.'" />'."\n";
 	    $result.='<td align="middle"><select name="'.
-		'GD_'.$uname.'_'.$part.'_sv" '.
-		'onChange="javascript:changeOneScore('.$part.',\''.$uname.'\')" >'."\n";
+		'GD_'.$uname.'_'.$part.'_solved" '.
+		'onChange="javascript:changeOneScore(\''.$part.'\',\''.$uname.'\')" >'."\n";
 	    my $optsel = '<option selected="on"> </option><option>excused</option>'."\n";
 	    $optsel = '<option> </option><option selected="on">excused</option>'."\n"
 		if ($status eq 'excused');
 	    $result.=$optsel;
 	    $result.="</select></td>\n";
+	} else {
+	    $result.='<input type="hidden" name="'.
+		'GD_'.$uname.'_'.$part.'_'.$type.'_s" value="'.$score.'" />'.
+		    "\n";
+	    $result.='<td align="middle"><input type="text" name="'.
+		'GD_'.$uname.'_'.$part.'_'.$type.'" '.
+		'value="'.$score.'" size="4" /></td>'."\n";
 	}
     }
     $result.='</tr>';
@@ -1745,20 +1767,40 @@ sub editgrades {
 
     my (@partid);
     my %weight = ();
+    my %columns = ();
     my ($i,$ctr,$count,$rec_update) = (0,0,0,0);
+
+    my (@parts) = sort(&getpartlist($url));
+    my $header;
     while ($ctr < $ENV{'form.totalparts'}) {
 	my $partid = $ENV{'form.partid_'.$ctr};
 	push @partid,$partid;
 	$weight{$partid} = $ENV{'form.weight_'.$partid};
 	$ctr++;
-	$result .= '<td colspan = 2 align="center"><b>Part '.$partid.
-	    '</b> (Weight = '.$weight{$partid}.')</td>';
     }
-    $result .= '</tr><tr bgcolor="#deffff">';
-    foreach (@partid) {
-	$result .= '<td align="center">&nbsp;<b>Old Score</b>&nbsp;</td>'.
+    foreach my $partid (@partid) {
+	$header .= '<td align="center">&nbsp;<b>Old Score</b>&nbsp;</td>'.
 	    '<td align="center">&nbsp;<b>New Score</b>&nbsp;</td>';
+	$columns{$partid}=2;
+	foreach my $stores (@parts) {
+	    my ($part,$type) = &split_part_type($stores);
+	    if ($part !~ m/^\Q$partid\E/) { next;}
+	    if ($type eq 'awarded' || $type eq 'solved') { next; }
+	    my $display=&Apache::lonnet::metadata($url,$stores.'.display');
+	    $display =~ s/\[Part: (\w)+\]//;
+	    $header .= '<td align="center">&nbsp;<b>Old</b> '.$display.'&nbsp;</td>'.
+		'<td align="center">&nbsp;<b>New</b> '.$display.'&nbsp;</td>';
+	    $columns{$partid}+=2;
+	}
     }
+    foreach my $partid (@partid) {
+	$result .= '<td colspan="'.$columns{$partid}.
+	    '" align="center"><b>Part '.$partid.
+	    '</b> (Weight = '.$weight{$partid}.')</td>';
+
+    }
+    $result .= '</tr><tr bgcolor="#deffff">';
+    $result .= $header;
     $result .= '</tr>'."\n";
 
     for ($i=0; $i<$ENV{'form.total'}; $i++) {
@@ -1766,38 +1808,54 @@ sub editgrades {
 	my %newrecord;
 	my $updateflag = 0;
 	my @userdom = grep /^$user:/,keys %$classlist;
-	my ($foo,$udom) = split(/:/,$userdom[0]);
+	my (undef,$udom) = split(/:/,$userdom[0]);
 
 	$result .= '<tr bgcolor="#ffffde"><td>'.$user.'&nbsp;</td><td>'.
 	    $$fullname{$userdom[0]}.'&nbsp;</td>';
-
 	foreach (@partid) {
-	    my $old_aw    = $ENV{'form.GD_'.$user.'_'.$_.'_aw_s'};
-	    my $old_part  = $old_aw eq '' ? '' : $old_aw/$weight{$_};
-	    my $old_score = $scoreptr{$ENV{'form.GD_'.$user.'_'.$_.'_sv_s'}};
-
-	    my $awarded   = $ENV{'form.GD_'.$user.'_'.$_.'_aw'};
-	    my $partial   = $awarded eq '' ? '' : $awarded/$weight{$_};
+	    my $old_aw    = $ENV{'form.GD_'.$user.'_'.$_.'_awarded_s'};
+	    my $old_part_pcr = $old_aw/($weight{$_} ne '0' ? $weight{$_}:1);
+	    my $old_part  = $old_aw eq '' ? '' : $old_part_pcr;
+	    my $old_score = $scoreptr{$ENV{'form.GD_'.$user.'_'.$_.'_solved_s'}};
+
+	    my $awarded   = $ENV{'form.GD_'.$user.'_'.$_.'_awarded'};
+	    my $pcr       = $awarded/($weight{$_} ne '0' ? $weight{$_} : 1);
+	    my $partial   = $awarded eq '' ? '' : $pcr;
 	    my $score;
 	    if ($partial eq '') {
-		$score = $scoreptr{$ENV{'form.GD_'.$user.'_'.$_.'_sv_s'}};
+		$score = $scoreptr{$ENV{'form.GD_'.$user.'_'.$_.'_solved_s'}};
 	    } elsif ($partial > 0) {
 		$score = 'correct_by_override';
 	    } elsif ($partial == 0) {
 		$score = 'incorrect_by_override';
 	    }
-	    $score = 'excused' if (($ENV{'form.GD_'.$user.'_'.$_.'_sv'} eq 'excused') &&
+	    $score = 'excused' if (($ENV{'form.GD_'.$user.'_'.$_.'_solved'} eq 'excused') &&
 				   ($score ne 'excused'));
 	    $result .= '<td align="center">'.$old_aw.'&nbsp;</td>'.
 		'<td align="center">'.$awarded.
 		($score eq 'excused' ? $score : '').'&nbsp;</td>';
 
-	    next if ($old_part eq $partial && $old_score eq $score);
-
-	    $updateflag = 1;
-	    $newrecord{'resource.'.$_.'.awarded'}  = $partial if $partial ne '';
-	    $newrecord{'resource.'.$_.'.solved'}   = $score;
-	    $rec_update++;
+	    if (!($old_part eq $partial && $old_score eq $score)) {
+		$updateflag = 1;
+		$newrecord{'resource.'.$_.'.awarded'}  = $partial if $partial ne '';
+		$newrecord{'resource.'.$_.'.solved'}   = $score;
+		$rec_update++;
+	    }
+
+	    my $partid=$_;
+	    foreach my $stores (@parts) {
+		my ($part,$type) = &split_part_type($stores);
+		if ($part !~ m/^\Q$partid\E/) { next;}
+		if ($type eq 'awarded' || $type eq 'solved') { next; }
+		my $old_aw    = $ENV{'form.GD_'.$user.'_'.$part.'_'.$type.'_s'};
+		my $awarded   = $ENV{'form.GD_'.$user.'_'.$part.'_'.$type};
+		if ($awarded ne '' && $awarded ne $old_aw) {
+		    $newrecord{'resource.'.$part.'.'.$type}= $awarded;
+		    $updateflag=1;
+		}
+		$result .= '<td align="center">'.$old_aw.'&nbsp;</td>'.
+		    '<td align="center">'.$awarded.'&nbsp;</td>';
+	    }
 	}
 	$result .= '</tr>'."\n";
 	if ($updateflag) {
@@ -1813,6 +1871,15 @@ sub editgrades {
 	'<b>Total number of students = '.$ENV{'form.total'}.'</b><br />';
     return $title.$msg.$result;
 }
+
+sub split_part_type {
+    my ($partstr) = @_;
+    my ($temp,@allparts)=split(/_/,$partstr);
+    my $type=pop(@allparts);
+    my $part=join('.',@allparts);
+    return ($part,$type);
+}
+
 #------------- end of section for handling grading by section/class ---------
 #
 #----------------------------------------------------------------------------
@@ -2029,8 +2096,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;
@@ -2119,18 +2184,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.='&nbsp;<b>View/Grade Entire Section/Class</b></td></tr>'."\n";
+    $result.='&nbsp;<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.='&nbsp;<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.='&nbsp;<input type="submit" name="submit" value="View/Grade" /></form>'."\n";
+    $result.='&nbsp;<input type="button" onClick="submit();" value="Grade" /></form>'."\n";
     $result.='</td></tr></table>'."\n";
     $result.='</td></tr></table>'."\n";
     return $result;
@@ -2140,7 +2207,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.='&nbsp;<b>Specify a file containing the class scores for above resource</b></td></tr>'."\n";
     $result.='<tr bgcolor=#ffffe6><td>'."\n";
@@ -2151,7 +2228,7 @@ sub upcsvScores_form {
 <input type="hidden" name="url" value="$url" />
 <input type="hidden" name="command" value="csvuploadmap" />
 $upfile_select
-<br />&nbsp;<input type="submit" name="submit" value="Upload Grades" />
+<br />&nbsp;<input type="button" onClick="javascript:checkUpload(this.form);" value="Upload Grades" />
 </form>
 ENDUPFORM
     $result.='</td></tr></table>'."\n";
@@ -2165,7 +2242,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.='&nbsp;<b>View/Grade an Individual Student\'s Submission</b></td></tr>'."\n";
+    $result.='&nbsp;<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".
@@ -2176,18 +2259,26 @@ sub viewGradeaStu_form {
 	'<input type="hidden" name="command" value="submission" />'."\n";
 
     $result.='&nbsp;<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.='&nbsp;&nbsp;<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.='&nbsp;(Section "no" implies the students were not assigned a section.)<br />' 
-	if (grep /no/,@$sections);
-    
-    $result.='<br />&nbsp;<input type="submit" name="submit" value="View/Grade" />'."\n".
-	'</form>'."\n";
+    if (ref($sections)) {
+	$result.='&nbsp;(Section "no" implies the students were not assigned a section.)<br />' 
+	    if (grep /no/,@$sections);
+    }
+
+
+    $result.='<br />&nbsp;<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;
@@ -2196,17 +2287,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.='&nbsp;<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.='&nbsp;<tt>'.$hostver.'-<input type="text" name="receipt" size="4"></tt><br />'."\n";
-    $result.='&nbsp;<input type="submit" name="submit" value="Verify Receipt">'."\n";
+    $result.='&nbsp;<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'}.'" />';
@@ -2268,7 +2369,6 @@ sub handler {
 	    }
 	}
     } 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 '');
@@ -2318,7 +2418,7 @@ sub send_header {
 #remotewindow=open('','homeworkremote');
 #remotewindow.close();
 #</script>"); 
-    $request->print('<body bgcolor="#FFFFFF">');
+    $request->print(&Apache::loncommon::bodytag('Grading'));
 }
 
 sub send_footer {