--- loncom/homework/grades.pm	2005/09/21 21:44:55	1.286
+++ loncom/homework/grades.pm	2005/12/02 19:40:47	1.300
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # The LON-CAPA Grading handler
 #
-# $Id: grades.pm,v 1.286 2005/09/21 21:44:55 albertel Exp $
+# $Id: grades.pm,v 1.300 2005/12/02 19:40:47 albertel Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -334,7 +334,16 @@ COMMONJSFUNCTIONS
 #--- section, ids and fullnames for each user.
 sub getclasslist {
     my ($getsec,$filterlist) = @_;
-    $getsec = $getsec eq '' ? 'all' : $getsec;
+    my @getsec;
+    if (!ref($getsec)) {
+	if ($getsec ne '' && $getsec ne 'all') {
+	    @getsec=($getsec);
+	}
+    } else {
+	@getsec=@{$getsec};
+    }
+    if (grep(/^all$/,@getsec)) { undef(@getsec); }
+
     my $classlist=&Apache::loncoursedata::get_classlist();
     # Bail out if we were unable to get the classlist
     return if (! defined($classlist));
@@ -363,7 +372,7 @@ sub getclasslist {
 	}
 	$section = ($section ne '' ? $section : 'none');
 	if (&canview($section)) {
-	    if ($getsec eq 'all' || $getsec eq $section) {
+	    if (!@getsec || grep(/^\Q$section\E$/,@getsec)) {
 		$sections{$section}++;
 		$fullnames{$student}=$fullname;
 	    } else {
@@ -536,7 +545,13 @@ sub verifyreceipt {
     if ($env{"course.$courseid.receiptalg"} eq 'receipt2') { $receiptparts=1; }
     my $parts=['0'];
     if ($receiptparts) { ($parts)=&response_type($url,$symb); }
-    foreach (sort {lc($$fullname{$a}) cmp lc($$fullname{$b}) } keys %$fullname) {
+    foreach (sort 
+	     {
+		 if (lc($$fullname{$a}) ne lc($$fullname{$b})) {
+		     return (lc($$fullname{$a}) cmp lc($$fullname{$b}));
+		 }
+		 return $a cmp $b;
+	     } (keys(%$fullname))) {
 	my ($uname,$udom)=split(/\:/);
 	foreach my $part (@$parts) {
 	    if ($receipt eq &Apache::lonnet::ireceipt($uname,$udom,$courseid,$symb,$part)) {
@@ -702,7 +717,14 @@ LISTJAVASCRIPT
     $gradeTable.='</tr>'."\n";
 
     my $ctr = 0;
-    foreach my $student (sort {lc($$fullname{$a}) cmp lc($$fullname{$b}) } keys %$fullname) {
+    foreach my $student (sort 
+			 {
+			     if (lc($$fullname{$a}) ne lc($$fullname{$b})) {
+				 return (lc($$fullname{$a}) cmp lc($$fullname{$b}));
+			     }
+			     return $a cmp $b;
+			 }
+			 (keys(%$fullname))) {
 	my ($uname,$udom) = split(/:/,$student);
 	my %status = ();
 	if ($env{'form.showgrading'} eq 'yes' && $submitonly ne 'all') {
@@ -1370,10 +1392,10 @@ sub gradeBox {
     my $ctr = 0;
     $result.='<table border="0"><tr>'."\n";  # display radio buttons in a nice table 10 across
     while ($ctr<=$wgt) {
-	$result.= '<td><nobr><input type="radio" name="RADVAL'.$counter.'_'.$partid.'" '.
+	$result.= '<td><nobr><label><input type="radio" name="RADVAL'.$counter.'_'.$partid.'" '.
 	    'onclick="javascript:writeBox(this.form,\''.$counter.'_'.$partid.'\','.
 	    $ctr.')" value="'.$ctr.'" '.
-	    ($score eq $ctr ? 'checked':'').' /> '.$ctr."</nobr></td>\n";
+	    ($score eq $ctr ? 'checked':'').' /> '.$ctr."</label></nobr></td>\n";
 	$result.=(($ctr+1)%10 == 0 ? '</tr><tr>' : '');
 	$ctr++;
     }
@@ -1822,13 +1844,24 @@ KEYWORDS
 	    '<input type="hidden" name="newmsg'.$counter.'" value="" />'."\n";
 	$result.='&nbsp;<a href="javascript:msgCenter(document.SCORE,'.$counter.
 	    ',\''.$msgfor.'\')"; TARGET=_self>'.
-	    'Compose Message to student'.(scalar(@col_fullnames) >= 1 ? 's' : '').'</a> &nbsp;'.
+	    &mt('Compose message to student').(scalar(@col_fullnames) >= 1 ? 's' : '').'</a> ('.
+	    &mt('incl. grades').' <input type="checkbox" name="withgrades'.$counter.'" />)'.
 	    '<img src="'.$request->dir_config('lonIconsURL').
 	    '/mailbkgrd.gif" width="14" height="10" name="mailicon'.$counter.'" />'."\n".
-	    '<br />&nbsp;(Message will be sent when you click on Save & Next below.)'."\n" 
-	    if ($env{'form.handgrade'} eq 'yes');
+	    '<br />&nbsp;('.
+	    &mt('Message will be sent when you click on Save & Next below.').")\n";
 	$request->print($result);
     }
+    if ($perm{'vgr'}) {
+	$request->print('<br />'.
+	    &Apache::loncommon::track_student_link(&mt('View recent activity'),
+						   $uname,$udom,'check'));
+    }
+    if ($perm{'opa'}) {
+	$request->print('<br />'.
+	    &Apache::loncommon::pprmlink(&mt('Set/Change parameters'),
+					 $uname,$udom,$symb,'check'));
+    }
 
     my %seen = ();
     my @partlist;
@@ -1944,18 +1977,24 @@ sub processHandGrade {
 	    my $includemsg = $env{'form.includemsg'.$ctr};
 	    my ($subject,$message,$msgstatus) = ('','','');
 	    if ($includemsg =~ /savemsg|newmsg\Q$ctr\E/) {
-		$subject = $env{'form.msgsub'} if ($includemsg =~ /^msgsub/);
+		$subject = $env{'form.msgsub'} if ($includemsg =~ /msgsub/);
+		unless ($subject=~/\w/) { $subject=&mt('Grading Feedback'); }
 		my (@msgnum) = split(/,/,$includemsg);
 		foreach (@msgnum) {
 		    $message.=$env{'form.'.$_} if ($_ =~ /savemsg|newmsg/ && $_ ne '');
 		}
 		$message =&Apache::lonfeedback::clear_out_html($message);
-		$message.="\n\nPoint".($pts > 1 ? 's':'').' awarded = '.$pts.' out of '.$wgt;
-		$message.=" for <a href=\"".
+		if ($env{'form.withgrades'.$ctr}) {
+		    $message.="\n\nPoint".($pts > 1 ? 's':'').' awarded = '.$pts.' out of '.$wgt;
+		    $message.=" for <a href=\"".
 		    &Apache::lonnet::clutter($url).
 		    "?symb=$symb\">$env{'form.probTitle'}</a>";
+		}
 		$msgstatus = &Apache::lonmsg::user_normal_msg ($uname,$udom,
-							       $env{'form.msgsub'},$message);
+							       $subject.' ['.
+							       &Apache::lonnet::declutter($url).']',$message);
+		$request->print('<br />'.&mt('Sending message to [_1]@[_2]',$uname,$udom).': '.
+				$msgstatus);
 	    }
 	    if ($env{'form.collaborator'.$ctr}) {
 		my @collabstrs=&Apache::loncommon::get_env_multiple("form.collaborator$ctr");
@@ -2064,7 +2103,13 @@ sub processHandGrade {
 
     my (@parsedlist,@nextlist);
     my ($nextflg) = 0;
-    foreach (sort {lc($$fullname{$a}) cmp lc($$fullname{$b}) } keys %$fullname) {
+    foreach (sort 
+	     {
+		 if (lc($$fullname{$a}) ne lc($$fullname{$b})) {
+		     return (lc($$fullname{$a}) cmp lc($$fullname{$b}));
+		 }
+		 return $a cmp $b;
+	     } (keys(%$fullname))) {
 	if ($nextflg == 1 && $button =~ /Next$/) {
 	    push @parsedlist,$_;
 	}
@@ -2394,6 +2439,7 @@ sub viewgrades_js {
 	}
 	for (i=0;i<document.classgrade.total.value;i++) {
 	    var user = document.classgrade["ctr"+i].value;
+	    user = user.replace(new RegExp(':', 'g'),"_");
 	    var scorename = document.classgrade["GD_"+user+"_"+partid+"_awarded"];
 	    var saveval   = document.classgrade["GD_"+user+"_"+partid+"_solved_s"].value;
 	    var selname   = document.classgrade["GD_"+user+"_"+partid+"_solved"];
@@ -2421,6 +2467,7 @@ sub viewgrades_js {
 
 	    for (i=0;i<document.classgrade.total.value;i++) {
 		var user = document.classgrade["ctr"+i].value;
+		user = user.replace(new RegExp(':', 'g'),"_");
 		var scorename = document.classgrade["GD_"+user+"_"+partid+"_awarded"];
 		var saveval   = document.classgrade["GD_"+user+"_"+partid+"_solved_s"].value;
 		var selname   = document.classgrade["GD_"+user+"_"+partid+"_solved"];
@@ -2438,6 +2485,7 @@ sub viewgrades_js {
 	} else {
 	    for (i=0;i<document.classgrade.total.value;i++) {
 		var user = document.classgrade["ctr"+i].value;
+		user = user.replace(new RegExp(':', 'g'),"_");
 		var scorename = document.classgrade["GD_"+user+"_"+partid+"_awarded"];
 		var saveval   = document.classgrade["GD_"+user+"_"+partid+"_solved_s"].value;
 		var selname   = document.classgrade["GD_"+user+"_"+partid+"_solved"];
@@ -2496,6 +2544,7 @@ sub viewgrades_js {
 
 	    for (i=0;i<document.classgrade.total.value;i++) {
 		var user = document.classgrade["ctr"+i].value;
+		user = user.replace(new RegExp(':', 'g'),"_");
 		var resetscore = document.classgrade["GD_"+user+"_"+partid+"_awarded"];
 		resetscore.value = document.classgrade["GD_"+user+"_"+partid+"_awarded_s"].value;
 		var resettries = document.classgrade["GD_"+user+"_"+partid+"_tries"];
@@ -2579,9 +2628,9 @@ sub viewgrades {
 	$result.='<table border="0"><tr>';  
 	my $ctr = 0;
 	while ($ctr<=$weight{$partid}) { # display radio buttons in a nice table 10 across
-	    $result.= '<td><input type="radio" name="RADVAL_'.$partid.'" '.
+	    $result.= '<td><label><input type="radio" name="RADVAL_'.$partid.'" '.
 		'onclick="javascript:writePoint(\''.$partid.'\','.$weight{$partid}.
-		','.$ctr.')" />'.$ctr."</td>\n";
+		','.$ctr.')" />'.$ctr."</label></td>\n";
 	    $result.=(($ctr+1)%10 == 0 ? '</tr><tr>' : '');
 	    $ctr++;
 	}
@@ -2638,7 +2687,13 @@ sub viewgrades {
     #list all the students - with points and grade status
     my (undef,undef,$fullname) = &getclasslist($env{'form.section'},'1');
     my $ctr = 0;
-    foreach (sort {lc($$fullname{$a}) cmp lc($$fullname{$b}) } keys %$fullname) {
+    foreach (sort 
+	     {
+		 if (lc($$fullname{$a}) ne lc($$fullname{$b})) {
+		     return (lc($$fullname{$a}) cmp lc($$fullname{$b}));
+		 }
+		 return $a cmp $b;
+	     } (keys(%$fullname))) {
 	$ctr++;
 	$result.=&viewstudentgrade($url,$symb,$env{'request.course.id'},
 				   $_,$$fullname{$_},\@parts,\%weight,$ctr,\%last_resets);
@@ -2822,13 +2877,14 @@ sub editgrades {
 	    my $dropMenu = $env{'form.GD_'.$user.'_'.$_.'_solved'};
 	    $score = 'excused' if (($dropMenu eq 'excused') && ($score ne 'excused'));
 
+	    $newrecord{'resource.'.$_.'.regrader'}=
+		"$env{'user.name'}:$env{'user.domain'}";
 	    if ($dropMenu eq 'reset status' &&
 		$old_score ne '') { # ignore if no previous attempts => nothing to reset
-		$newrecord{'resource.'.$_.'.tries'} = 0;
+		$newrecord{'resource.'.$_.'.tries'} = '';
 		$newrecord{'resource.'.$_.'.solved'} = '';
 		$newrecord{'resource.'.$_.'.award'} = '';
-		$newrecord{'resource.'.$_.'.awarded'} = 0;
-		$newrecord{'resource.'.$_.'.regrader'}="$env{'user.name'}:$env{'user.domain'}";
+		$newrecord{'resource.'.$_.'.awarded'} = '';
 		$updateflag = 1;
                 if ($env{'form.GD_'.$user.'_'.$_.'_aggtries'} > 0) {
                     my $aggtries = $env{'form.GD_'.$user.'_'.$_.'_aggtries'};
@@ -3162,7 +3218,6 @@ sub csvuploadoptions {
 <form method="post" enctype="multipart/form-data" action="/adm/grades" name="gradesupload">
 <h3><font color="#339933">Uploading Class Grade Options</font></h3>
 <input type="hidden" name="command"    value="csvuploadassign" />
-<input type="submit" value="Assign Grades" /><br />
 <p>
 <label>
    <input type="checkbox" name="show_full_results" />
@@ -3190,7 +3245,8 @@ ENDPICK
     }
     # FIXME do a check for any duplicated user ids...
     # FIXME do a check for any invalid user ids?...
-    $request->print("<hr /></form>\n");
+    $request->print('<input type="submit" value="Assign Grades" /><br />
+<hr /></form>'."\n");
     $request->print(&show_grading_menu_form($symb,$url));
     return '';
 }
@@ -3365,13 +3421,13 @@ LISTJAVASCRIPT
     $result.='<input type="hidden" name="page" />'."\n".
 	'<input type="hidden" name="title" />'."\n";
 
-    $result.='&nbsp;<b>View Problems Text: </b><input type="radio" name="vProb" value="no" checked="on" /> no '."\n".
-	'<input type="radio" name="vProb" value="yes" /> yes '."<br>\n";
+    $result.='&nbsp;<b>View Problems Text: </b><label><input type="radio" name="vProb" value="no" checked="on" /> no </label>'."\n".
+	'<label><input type="radio" name="vProb" value="yes" /> yes </label>'."<br />\n";
 
     $result.='&nbsp;<b>Submission Details: </b>'.
-	'<input type="radio" name="lastSub" value="none" /> none'."\n".
-	'<input type="radio" name="lastSub" value="datesub" checked /> by dates and submissions'."\n".
-	'<input type="radio" name="lastSub" value="all" /> all details'."\n";
+	'<label><input type="radio" name="lastSub" value="none" /> none</label>'."\n".
+	'<label><input type="radio" name="lastSub" value="datesub" checked /> by dates and submissions</label>'."\n".
+	'<label><input type="radio" name="lastSub" value="all" /> all details</label>'."\n";
 
     $result.='<input type="hidden" name="section"     value="'.$getsec.'" />'."\n".
 	'<input type="hidden" name="Status"  value="'.$env{'form.Status'}.'" />'."\n".
@@ -3395,12 +3451,18 @@ LISTJAVASCRIPT
  
     my (undef,undef,$fullname) = &getclasslist($getsec,'1');
     my $ptr = 1;
-    foreach my $student (sort {lc($$fullname{$a}) cmp lc($$fullname{$b}) } keys %$fullname) {
+    foreach my $student (sort 
+			 {
+			     if (lc($$fullname{$a}) ne lc($$fullname{$b})) {
+				 return (lc($$fullname{$a}) cmp lc($$fullname{$b}));
+			     }
+			     return $a cmp $b;
+			 } (keys(%$fullname))) {
 	my ($uname,$udom) = split(/:/,$student);
 	$studentTable.=($ptr%2 == 1 ? '<tr bgcolor="#ffffe6">' : '</td>');
 	$studentTable.='<td align="right">'.$ptr.'&nbsp;</td>';
-	$studentTable.='<td>&nbsp;<input type="radio" name="student" value="'.$student.'" /> '
-	    .&nameUserString(undef,$$fullname{$student},$uname,$udom)."\n";
+	$studentTable.='<td>&nbsp;<label><input type="radio" name="student" value="'.$student.'" /> '
+	    .&nameUserString(undef,$$fullname{$student},$uname,$udom)."</label>\n";
 	$studentTable.=($ptr%2 == 0 ? '</td></tr>' : '');
 	$ptr++;
     }
@@ -3472,7 +3534,11 @@ sub displayPage {
     my $navmap = Apache::lonnavmaps::navmap->new();
     my ($mapUrl, $id, $resUrl)=&Apache::lonnet::decode_symb($env{'form.page'});
     my $map = $navmap->getResourceByUrl($resUrl); # add to navmaps
-
+    if (!$map) {
+	$request->print('<font color="red">Unable to view requested sequence. ('.$resUrl.')</font>');
+	$request->print(&show_grading_menu_form($symb,$url));
+	return; 
+    }
     my $iterator = $navmap->getIterator($map->map_start(),
 					$map->map_finish());
 
@@ -3678,7 +3744,12 @@ sub updateGradeByPage {
     my $navmap = Apache::lonnavmaps::navmap->new();
     my ($mapUrl, $id, $resUrl) = &Apache::lonnet::decode_symb( $env{'form.page'});
     my $map = $navmap->getResourceByUrl($resUrl); # add to navmaps
-
+    if (!$map) {
+	$request->print('<font color="red">Unable to grade requested sequence. ('.$resUrl.')</font>');
+	my ($symb,$url)=&get_symb_and_url($request);
+	$request->print(&show_grading_menu_form($symb,$url));
+	return; 
+    }
     my $iterator = $navmap->getIterator($map->map_start(),
 					$map->map_finish());
 
@@ -4018,7 +4089,7 @@ SCANTRONFORM
             </tr>
             <tr bgcolor="#ffffe6">
               <td colspan="2">
-                <input type="submit" value="Show List of Files" />
+                <input type="submit" value="Download: Show List of Associated Files" />
               </td>
             </tr>
           </table>
@@ -4324,7 +4395,7 @@ sub scantron_process_corrections {
 	}
     }
     if ($err) {
-	$r->print("Unable to accept last correction, an error occurred :$errmsg:");
+	$r->print("<font color='red'>Unable to accept last correction, an error occurred :$errmsg:</font>");
     } else {
 	&scantron_put_line($scanlines,$scan_data,$which,$line,$skip);
 	&scantron_putfile($scanlines,$scan_data);
@@ -5390,10 +5461,10 @@ GRADINGMENUJS
 
     $result.='</td></tr>';
 
-    $result.='<tr bgcolor="#ffffe6"valign="top"><td>'.
+    $result.='<tr bgcolor="#ffffe6"valign="top"><td><label>'.
 	'<input type="radio" name="radioChoice" value="submission" '.
 	($saveCmd eq 'submission' ? 'checked' : '').'> '.'<b>'.&mt('Current Resource').':</b> '.&mt('For one or more students').
-	' <select name="submitonly">'.
+	'</label> <select name="submitonly">'.
 	'<option value="yes" '.
 	($saveSub eq 'yes' ? 'selected="on"' : '').'>with submissions</option>'.
 	'<option value="graded" '.
@@ -5404,14 +5475,14 @@ GRADINGMENUJS
 	($saveSub eq 'all' ? 'selected="on"' : '').'>with any status</option></select></td></tr>'."\n";
 
     $result.='<tr bgcolor="#ffffe6"valign="top"><td>'.
-	'<input type="radio" name="radioChoice" value="viewgrades" '.
+	'<label><input type="radio" name="radioChoice" value="viewgrades" '.
 	($saveCmd eq 'viewgrades' ? 'checked' : '').'> '.
-	'<b>Current Resource:</b> For all students in selected section or course</td></tr>'."\n";
+	'<b>Current Resource:</b> For all students in selected section or course</label></td></tr>'."\n";
 
     $result.='<tr bgcolor="#ffffe6" valign="top"><td>'.
-	'<input type="radio" name="radioChoice" value="pickStudentPage" '.
+	'<label><input type="radio" name="radioChoice" value="pickStudentPage" '.
 	($saveCmd eq 'pickStudentPage' ? 'checked' : '').'> '.
-	'The <b>complete</b> set/page/sequence: For one student</td></tr>'."\n";
+	'The <b>complete</b> set/page/sequence: For one student</label></td></tr>'."\n";
 
     $result.='<tr bgcolor="#ffffe6"><td><br />'.
 	'<input type="button" onClick="javascript:checkChoice(this.form,\'2\');" value="Next->" />'.
@@ -5455,18 +5526,18 @@ sub reset_perm {
 
 sub init_perm {
     &reset_perm();
-    if (!($perm{'vgr'}=&Apache::lonnet::allowed('vgr',$env{'request.course.id'}))) {
-	if ($perm{'vgr'}=&Apache::lonnet::allowed('vgr',$env{'request.course.id'}.'/'.$env{'request.course.sec'})) {
-	    $perm{'vgr_section'}=$env{'request.course.sec'};
-	} else {
-	    delete($perm{'vgr'});
-	}
-    }
-    if (!($perm{'mgr'}=&Apache::lonnet::allowed('mgr',$env{'request.course.id'}))) {
-	if ($perm{'mgr'}=&Apache::lonnet::allowed('mgr',$env{'request.course.id'}.'/'.$env{'request.course.sec'})) {
-	    $perm{'mgr_section'}=$env{'request.course.sec'};
-	} else {
-	    delete($perm{'mgr'});
+    foreach my $test_perm ('vgr','mgr','opa') {
+
+	my $scope = $env{'request.course.id'};
+	if (!($perm{$test_perm}=&Apache::lonnet::allowed($test_perm,$scope))) {
+
+	    $scope .= '/'.$env{'request.course.sec'};
+	    if ( $perm{$test_perm}=
+		 &Apache::lonnet::allowed($test_perm,$scope)) {
+		$perm{$test_perm.'_section'}=$env{'request.course.sec'};
+	    } else {
+		delete($perm{$test_perm});
+	    }
 	}
     }
 }