Diff for /loncom/homework/grades.pm between versions 1.441 and 1.477

version 1.441, 2007/09/27 19:44:51 version 1.477, 2007/11/03 00:08:09
Line 35  use Apache::loncommon; Line 35  use Apache::loncommon;
 use Apache::lonhtmlcommon;  use Apache::lonhtmlcommon;
 use Apache::lonnavmaps;  use Apache::lonnavmaps;
 use Apache::lonhomework;  use Apache::lonhomework;
   use Apache::lonpickcode;
 use Apache::loncoursedata;  use Apache::loncoursedata;
 use Apache::lonmsg();  use Apache::lonmsg();
 use Apache::Constants qw(:common);  use Apache::Constants qw(:common);
Line 47  use POSIX qw(floor); Line 48  use POSIX qw(floor);
   
   
 my %perm=();  my %perm=();
 my %bubble_lines_per_response;     # no. bubble lines for each response.  my %bubble_lines_per_response = ();     # no. bubble lines for each response.
                                    # index is "symb.part_id"                                     # index is "symb.part_id"
   
   my %first_bubble_line = (); # First bubble line no. for each bubble.
   
   # Save and restore the bubble lines array to the form env.
   
   
   sub save_bubble_lines {
       foreach my $line (keys(%bubble_lines_per_response)) {
    $env{"form.scantron.bubblelines.$line"}  = $bubble_lines_per_response{$line};
    $env{"form.scantron.first_bubble_line.$line"} =
       $first_bubble_line{$line};
       }
   }
   
   
   sub restore_bubble_lines {
       my $line = 0;
       %bubble_lines_per_response = ();
       while ($env{"form.scantron.bubblelines.$line"}) {
    my $value = $env{"form.scantron.bubblelines.$line"};
    $bubble_lines_per_response{$line} = $value;
    $first_bubble_line{$line}  =
       $env{"form.scantron.first_bubble_line.$line"};
    $line++;
       }
   
   }
   
   #  Given the parsed scanline, get the response for 
   #  'answer' number n:
   
   sub get_response_bubbles {
       my ($parsed_line, $response)  = @_;
   
   
       my $bubble_line = $first_bubble_line{$response-1} +1;
       my $bubble_lines= $bubble_lines_per_response{$response-1};
       
       my $selected = "";
   
       for (my $bline = 0; $bline < $bubble_lines; $bline++) {
    $selected .= $$parsed_line{"scantron.$bubble_line.answer"}.":";
    $bubble_line++;
       }
       return $selected;
   }
   
   
 # ----- These first few routines are general use routines.----  # ----- These first few routines are general use routines.----
   
   # Return the number of occurences of a pattern in a string.
   
   sub occurence_count {
       my ($string, $pattern) = @_;
   
       my @matches = ($string =~ /$pattern/g);
   
       return scalar(@matches);
   }
   
   
   # Take a string known to have digits and convert all the
   # digits into letters in the range J,A..I.
   
   sub digits_to_letters {
       my ($input) = @_;
   
       my @alphabet = ('J', 'A'..'I');
   
       my @input    = split(//, $input);
       my $output ='';
       for (my $i = 0; $i < scalar(@input); $i++) {
    if ($input[$i] =~ /\d/) {
       $output .= $alphabet[$input[$i]];
    } else {
       $output .= $input[$i];
    }
       }
       return $output;
   }
   
 #  #
 # --- Retrieve the parts from the metadata file.---  # --- Retrieve the parts from the metadata file.---
 sub getpartlist {  sub getpartlist {
Line 253  sub cleanRecord { Line 332  sub cleanRecord {
     $bottomrow.='<td>'.$grayFont.$foil.'</span>&nbsp;</td>';      $bottomrow.='<td>'.$grayFont.$foil.'</span>&nbsp;</td>';
  }   }
  return '<blockquote><table border="1">'.   return '<blockquote><table border="1">'.
     '<tr valign="top"><td>Answer</td>'.$toprow.'</tr>'.      '<tr valign="top"><td>'.&mt('Answer').'</td>'.$toprow.'</tr>'.
     '<tr valign="top"><td>'.$grayFont.'Option ID</span></td>'.      '<tr valign="top"><td>'.$grayFont.&mt('Option ID').'</span></td>'.
     $grayFont.$bottomrow.'</tr>'.'</table></blockquote>';      $grayFont.$bottomrow.'</tr>'.'</table></blockquote>';
     } elsif ($response eq 'match') {      } elsif ($response eq 'match') {
  my %answer=&Apache::lonnet::str2hash($answer);   my %answer=&Apache::lonnet::str2hash($answer);
Line 273  sub cleanRecord { Line 352  sub cleanRecord {
     $bottomrow.='<td>'.$grayFont.$foil.'</span>&nbsp;</td>';      $bottomrow.='<td>'.$grayFont.$foil.'</span>&nbsp;</td>';
  }   }
  return '<blockquote><table border="1">'.   return '<blockquote><table border="1">'.
     '<tr valign="top"><td>Answer</td>'.$toprow.'</tr>'.      '<tr valign="top"><td>'.&mt('Answer').'</td>'.$toprow.'</tr>'.
     '<tr valign="top"><td>'.$grayFont.'Item ID</span></td>'.      '<tr valign="top"><td>'.$grayFont.&mt('Item ID').'</span></td>'.
     $middlerow.'</tr>'.      $middlerow.'</tr>'.
     '<tr valign="top"><td>'.$grayFont.'Option ID</span></td>'.      '<tr valign="top"><td>'.$grayFont.&mt('Option ID').'</span></td>'.
     $bottomrow.'</tr>'.'</table></blockquote>';      $bottomrow.'</tr>'.'</table></blockquote>';
     } elsif ($response eq 'radiobutton') {      } elsif ($response eq 'radiobutton') {
  my %answer=&Apache::lonnet::str2hash($answer);   my %answer=&Apache::lonnet::str2hash($answer);
Line 286  sub cleanRecord { Line 365  sub cleanRecord {
  foreach my $foil (@$order) {   foreach my $foil (@$order) {
     if (exists($answer{$foil})) {      if (exists($answer{$foil})) {
  if ($foil eq $correct) {   if ($foil eq $correct) {
     $toprow.='<td><b>true</b></td>';      $toprow.='<td><b>'.&mt('true').'</b></td>';
  } else {   } else {
     $toprow.='<td><i>true</i></td>';      $toprow.='<td><i>'.&mt('true').'</i></td>';
  }   }
     } else {      } else {
  $toprow.='<td>false</td>';   $toprow.='<td>'.&mt('false').'</td>';
     }      }
     $bottomrow.='<td>'.$grayFont.$foil.'</span>&nbsp;</td>';      $bottomrow.='<td>'.$grayFont.$foil.'</span>&nbsp;</td>';
  }   }
  return '<blockquote><table border="1">'.   return '<blockquote><table border="1">'.
     '<tr valign="top"><td>Answer</td>'.$toprow.'</tr>'.      '<tr valign="top"><td>'.&mt('Answer').'</td>'.$toprow.'</tr>'.
     '<tr valign="top"><td>'.$grayFont.'Option ID</span></td>'.      '<tr valign="top"><td>'.$grayFont.&mt('Option ID').'</span></td>'.
     $grayFont.$bottomrow.'</tr>'.'</table></blockquote>';      $grayFont.$bottomrow.'</tr>'.'</table></blockquote>';
     } elsif ($response eq 'essay') {      } elsif ($response eq 'essay') {
  if (! exists ($env{'form.'.$symb})) {   if (! exists ($env{'form.'.$symb})) {
Line 396  COMMONJSFUNCTIONS Line 475  COMMONJSFUNCTIONS
 #--- Dumps the class list with usernames,list of sections,  #--- Dumps the class list with usernames,list of sections,
 #--- section, ids and fullnames for each user.  #--- section, ids and fullnames for each user.
 sub getclasslist {  sub getclasslist {
     my ($getsec,$filterlist) = @_;      my ($getsec,$filterlist,$getgroup) = @_;
     my @getsec;      my @getsec;
       my @getgroup;
       my $stu_status = join(':',&Apache::loncommon::get_env_multiple('form.Status'));
     if (!ref($getsec)) {      if (!ref($getsec)) {
  if ($getsec ne '' && $getsec ne 'all') {   if ($getsec ne '' && $getsec ne 'all') {
     @getsec=($getsec);      @getsec=($getsec);
Line 406  sub getclasslist { Line 487  sub getclasslist {
  @getsec=@{$getsec};   @getsec=@{$getsec};
     }      }
     if (grep(/^all$/,@getsec)) { undef(@getsec); }      if (grep(/^all$/,@getsec)) { undef(@getsec); }
       if (!ref($getgroup)) {
    if ($getgroup ne '' && $getgroup ne 'all') {
       @getgroup=($getgroup);
    }
       } else {
    @getgroup=@{$getgroup};
       }
       if (grep(/^all$/,@getgroup)) { undef(@getgroup); }
   
     my $classlist=&Apache::loncoursedata::get_classlist();      my ($classlist,$keylist)=&Apache::loncoursedata::get_classlist();
     # Bail out if we were unable to get the classlist      # Bail out if we were unable to get the classlist
     return if (! defined($classlist));      return if (! defined($classlist));
       &Apache::loncoursedata::get_group_memberships($classlist,$keylist);
     #      #
     my %sections;      my %sections;
     my %fullnames;      my %fullnames;
Line 426  sub getclasslist { Line 516  sub getclasslist {
             $classlist->{$student}->[&Apache::loncoursedata::CL_FULLNAME()];              $classlist->{$student}->[&Apache::loncoursedata::CL_FULLNAME()];
         my $status   =           my $status   = 
             $classlist->{$student}->[&Apache::loncoursedata::CL_STATUS()];              $classlist->{$student}->[&Apache::loncoursedata::CL_STATUS()];
           my $group   = 
               $classlist->{$student}->[&Apache::loncoursedata::CL_GROUP()];
  # filter students according to status selected   # filter students according to status selected
  if ($filterlist && $env{'form.Status'} ne 'Any') {   if ($filterlist && (!($stu_status =~ /Any/))) {
     if ($env{'form.Status'} ne $status) {      if (!($stu_status =~ $status)) {
  delete ($classlist->{$student});   delete($classlist->{$student});
  next;   next;
     }      }
  }   }
    # filter students according to groups selected
    my @stu_groups = split(/,/,$group);
    if (@getgroup) {
       my $exclude = 1;
       foreach my $grp (@getgroup) {
           foreach my $stu_group (@stu_groups) {
               if ($stu_group eq $grp) {
                   $exclude = 0;
                  } 
           }
              if (($grp eq 'none') && !$group) {
                  $exclude = 0;
           }
       }
       if ($exclude) {
           delete($classlist->{$student});
       }
    }
  $section = ($section ne '' ? $section : 'none');   $section = ($section ne '' ? $section : 'none');
  if (&canview($section)) {   if (&canview($section)) {
     if (!@getsec || grep(/^\Q$section\E$/,@getsec)) {      if (!@getsec || grep(/^\Q$section\E$/,@getsec)) {
  $sections{$section}++;   $sections{$section}++;
  $fullnames{$student}=$fullname;   if ($classlist->{$student}) {
       $fullnames{$student}=$fullname;
    }
     } else {      } else {
  delete($classlist->{$student});   delete($classlist->{$student});
     }      }
Line 510  sub student_gradeStatus { Line 622  sub student_gradeStatus {
 # Shows a student's view of problem and submission  # Shows a student's view of problem and submission
 sub jscriptNform {  sub jscriptNform {
     my ($symb) = @_;      my ($symb) = @_;
       my $stu_status = join(':',&Apache::loncommon::get_env_multiple('form.Status'));
     my $jscript='<script type="text/javascript" language="javascript">'."\n".      my $jscript='<script type="text/javascript" language="javascript">'."\n".
  '    function viewOneStudent(user,domain) {'."\n".   '    function viewOneStudent(user,domain) {'."\n".
  ' document.onestudent.student.value = user;'."\n".   ' document.onestudent.student.value = user;'."\n".
Line 521  sub jscriptNform { Line 634  sub jscriptNform {
  '<input type="hidden" name="symb"    value="'.&Apache::lonenc::check_encrypt($symb).'" />'."\n".   '<input type="hidden" name="symb"    value="'.&Apache::lonenc::check_encrypt($symb).'" />'."\n".
  '<input type="hidden" name="saveState" value="'.$env{'form.saveState'}.'" />'."\n".   '<input type="hidden" name="saveState" value="'.$env{'form.saveState'}.'" />'."\n".
  '<input type="hidden" name="probTitle" value="'.$env{'form.probTitle'}.'" />'."\n".   '<input type="hidden" name="probTitle" value="'.$env{'form.probTitle'}.'" />'."\n".
  '<input type="hidden" name="Status"  value="'.$env{'form.Status'}.'" />'."\n".   '<input type="hidden" name="Status"  value="'.$stu_status.'" />'."\n".
  '<input type="hidden" name="command" value="submission" />'."\n".   '<input type="hidden" name="command" value="submission" />'."\n".
  '<input type="hidden" name="student" value="" />'."\n".   '<input type="hidden" name="student" value="" />'."\n".
  '<input type="hidden" name="userdom" value="" />'."\n".   '<input type="hidden" name="userdom" value="" />'."\n".
Line 529  sub jscriptNform { Line 642  sub jscriptNform {
     return $jscript;      return $jscript;
 }  }
   
   
   
 # Given the score (as a number [0-1] and the weight) what is the final  # Given the score (as a number [0-1] and the weight) what is the final
 # point value? This function will round to the nearest tenth, third,  # point value? This function will round to the nearest tenth, third,
 # or quarter if one of those is within the tolerance of .00001.  # or quarter if one of those is within the tolerance of .00001.
Line 685  sub listStudents { Line 800  sub listStudents {
     my $cdom      = $env{"course.$env{'request.course.id'}.domain"};      my $cdom      = $env{"course.$env{'request.course.id'}.domain"};
     my $cnum      = $env{"course.$env{'request.course.id'}.num"};      my $cnum      = $env{"course.$env{'request.course.id'}.num"};
     my $getsec    = $env{'form.section'} eq '' ? 'all' : $env{'form.section'};      my $getsec    = $env{'form.section'} eq '' ? 'all' : $env{'form.section'};
       my $getgroup  = $env{'form.group'} eq '' ? 'all' : $env{'form.group'};
     my $submitonly= $env{'form.submitonly'} eq '' ? 'all' : $env{'form.submitonly'};      my $submitonly= $env{'form.submitonly'} eq '' ? 'all' : $env{'form.submitonly'};
   
     my $viewgrade = $env{'form.showgrading'} eq 'yes' ? 'View/Grade/Regrade' : 'View';      my $viewgrade = $env{'form.showgrading'} eq 'yes' ? 'View/Grade/Regrade' : 'View';
     $env{'form.probTitle'} = $env{'form.probTitle'} eq '' ?       $env{'form.probTitle'} = $env{'form.probTitle'} eq '' ? 
  &Apache::lonnet::gettitle($symb) : $env{'form.probTitle'};   &Apache::lonnet::gettitle($symb) : $env{'form.probTitle'};
Line 746  LISTJAVASCRIPT Line 861  LISTJAVASCRIPT
     if ($env{'form.handgrade'} eq 'yes' && scalar(@$partlist) > 1) {      if ($env{'form.handgrade'} eq 'yes' && scalar(@$partlist) > 1) {
  $gradeTable.='<label><input type="radio" name="lastSub" value="hdgrade" '.$checkhdgrade.' /> essay part only </label>'."\n";   $gradeTable.='<label><input type="radio" name="lastSub" value="hdgrade" '.$checkhdgrade.' /> essay part only </label>'."\n";
     }      }
       my $stu_status = join(':',&Apache::loncommon::get_env_multiple('form.Status'));
     my $saveStatus = $env{'form.Status'} eq '' ? 'Active' : $env{'form.Status'};      my $saveStatus = $stu_status eq '' ? 'Active' : $stu_status;
     $env{'form.Status'} = $saveStatus;      $env{'form.Status'} = $saveStatus;
     $gradeTable.='<label><input type="radio" name="lastSub" value="lastonly" '.$checklastsub.' /> last submission only </label>'."\n".      $gradeTable.='<label><input type="radio" name="lastSub" value="lastonly" '.$checklastsub.' /> last submission only </label>'."\n".
  '<label><input type="radio" name="lastSub" value="last" /> last submission & parts info </label>'."\n".   '<label><input type="radio" name="lastSub" value="last" /> last submission &amp; parts info </label>'."\n".
  '<label><input type="radio" name="lastSub" value="datesub" /> by dates and submissions </label>'."\n".   '<label><input type="radio" name="lastSub" value="datesub" /> by dates and submissions </label>'."\n".
  '<label><input type="radio" name="lastSub" value="all" /> all details</label><br />'."\n".   '<label><input type="radio" name="lastSub" value="all" /> all details</label><br />'."\n".
         '&nbsp;<b>Grading Increments:</b> <select name="increment">'.          '&nbsp;<b>Grading Increments:</b> <select name="increment">'.
Line 769  LISTJAVASCRIPT Line 884  LISTJAVASCRIPT
  '<input type="hidden" name="saveStatusOld" value="'.$saveStatus.'" />'."\n";   '<input type="hidden" name="saveStatusOld" value="'.$saveStatus.'" />'."\n";
   
     if (exists($env{'form.gradingMenu'}) && exists($env{'form.Status'})) {      if (exists($env{'form.gradingMenu'}) && exists($env{'form.Status'})) {
  $gradeTable.='<input type="hidden" name="Status"   value="'.$env{'form.Status'}.'" />'."\n";   $gradeTable.='<input type="hidden" name="Status"   value="'.$stu_status.'" />'."\n";
     } else {      } else {
  $gradeTable.='<b>Student Status:</b> '.   $gradeTable.='<b>Student Status:</b> '.
     &Apache::lonhtmlcommon::StatusOptions($saveStatus,undef,1,'javascript:reLoadList(this.form);').'<br />';      &Apache::lonhtmlcommon::StatusOptions($saveStatus,undef,1,'javascript:reLoadList(this.form);').'<br />';
Line 786  LISTJAVASCRIPT Line 901  LISTJAVASCRIPT
  'value="Next->" /> <br />'."\n";   'value="Next->" /> <br />'."\n";
     $gradeTable.=&check_buttons();      $gradeTable.=&check_buttons();
     $gradeTable.='<label><input type="checkbox" name="checkPlag" checked="checked" />Check For Plagiarism</label>';      $gradeTable.='<label><input type="checkbox" name="checkPlag" checked="checked" />Check For Plagiarism</label>';
     my ($classlist, undef, $fullname) = &getclasslist($getsec,'1');      my ($classlist, undef, $fullname) = &getclasslist($getsec,'1',$getgroup);
     $gradeTable.='<table border="0"><tr><td bgcolor="#777777">'.      $gradeTable.= &Apache::loncommon::start_data_table().
  '<table border="0"><tr bgcolor="#e6ffff">';   &Apache::loncommon::start_data_table_header_row();
     my $loop = 0;      my $loop = 0;
     while ($loop < 2) {      while ($loop < 2) {
  $gradeTable.='<td><b>&nbsp;No.</b>&nbsp;</td><td><b>&nbsp;Select&nbsp;</b></td>'.   $gradeTable.='<th>No.</th><th>Select</th>'.
     '<td>'.&nameUserString('header').'&nbsp;Section/Group</td>';      '<th>'.&nameUserString('header').'&nbsp;'.'Section/Group</th>';
  if ($env{'form.showgrading'} eq 'yes'    if ($env{'form.showgrading'} eq 'yes' 
     && $submitonly ne 'queued'      && $submitonly ne 'queued'
     && $submitonly ne 'all') {      && $submitonly ne 'all') {
     foreach (sort(@$partlist)) {      foreach (sort(@$partlist)) {
  my $display_part=&get_display_part((split(/_/))[0],$symb);   my $display_part=&get_display_part((split(/_/))[0],$symb);
  $gradeTable.='<td><b>&nbsp;Part: '.$display_part.   $gradeTable.='<th>Part: '.$display_part.
     ' Status&nbsp;</b></td>';      ' Status</h>';
     }      }
  } elsif ($submitonly eq 'queued') {   } elsif ($submitonly eq 'queued') {
     $gradeTable.='<td><b>&nbsp;'.&mt('Queue Status').'&nbsp;</b></td>';      $gradeTable.='<th>'.&mt('Queue Status').'&nbsp;</th>';
  }   }
  $loop++;   $loop++;
 # $gradeTable.='<td></td>' if ($loop%2 ==1);  # $gradeTable.='<td></td>' if ($loop%2 ==1);
     }      }
     $gradeTable.='</tr>'."\n";      $gradeTable.=&Apache::loncommon::end_data_table_header_row()."\n";
   
     my $ctr = 0;      my $ctr = 0;
     foreach my $student (sort       foreach my $student (sort 
Line 861  LISTJAVASCRIPT Line 976  LISTJAVASCRIPT
   
  $ctr++;   $ctr++;
  my $section = $classlist->{$student}->[&Apache::loncoursedata::CL_SECTION()];   my $section = $classlist->{$student}->[&Apache::loncoursedata::CL_SECTION()];
           my $group = $classlist->{$student}->[&Apache::loncoursedata::CL_GROUP()];
  if ( $perm{'vgr'} eq 'F' ) {   if ( $perm{'vgr'} eq 'F' ) {
     $gradeTable.='<tr bgcolor="#ffffe6">' if ($ctr%2 ==1);      if ($ctr%2 ==1) {
    $gradeTable.= &Apache::loncommon::start_data_table_row();
       }
     $gradeTable.='<td align="right">'.$ctr.'&nbsp;</td>'.      $gradeTable.='<td align="right">'.$ctr.'&nbsp;</td>'.
                '<td align="center"><label><input type=checkbox name="stuinfo" value="'.                 '<td align="center"><label><input type=checkbox name="stuinfo" value="'.
                $student.':'.$$fullname{$student}.':::SECTION'.$section.                 $student.':'.$$fullname{$student}.':::SECTION'.$section.
        ')&nbsp;" />&nbsp;&nbsp;</label></td>'."\n".'<td>'.         ')&nbsp;" />&nbsp;&nbsp;</label></td>'."\n".'<td>'.
        &nameUserString(undef,$$fullname{$student},$uname,$udom).         &nameUserString(undef,$$fullname{$student},$uname,$udom).
        '&nbsp;'.$section.'</td>'."\n";         '&nbsp;'.$section.($group ne '' ?'/'.$group:'').'</td>'."\n";
   
     if ($env{'form.showgrading'} eq 'yes' && $submitonly ne 'all') {      if ($env{'form.showgrading'} eq 'yes' && $submitonly ne 'all') {
  foreach (sort keys(%status)) {   foreach (sort keys(%status)) {
Line 878  LISTJAVASCRIPT Line 995  LISTJAVASCRIPT
  }   }
     }      }
 #    $gradeTable.='<td></td>' if ($ctr%2 ==1);  #    $gradeTable.='<td></td>' if ($ctr%2 ==1);
     $gradeTable.='</tr>'."\n" if ($ctr%2 ==0);      if ($ctr%2 ==0) {
    $gradeTable.=&Apache::loncommon::end_data_table_row()."\n";
       }
  }   }
     }      }
     if ($ctr%2 ==1) {      if ($ctr%2 ==1) {
Line 892  LISTJAVASCRIPT Line 1011  LISTJAVASCRIPT
     } elsif ($submitonly eq 'queued') {      } elsif ($submitonly eq 'queued') {
  $gradeTable.='<td>&nbsp;</td>';   $gradeTable.='<td>&nbsp;</td>';
     }      }
  $gradeTable.='</tr>';   $gradeTable.=&Apache::loncommon::end_data_table_row();
     }      }
   
     $gradeTable.='</table></td></tr></table>'."\n".      $gradeTable.=&Apache::loncommon::end_data_table()."\n".
  '<input type="button" '.   '<input type="button" '.
  'onClick="javascript:checkSelect(this.form.stuinfo);" '.   'onClick="javascript:checkSelect(this.form.stuinfo);" '.
  'value="Next->" /></form>'."\n";   'value="Next->" /></form>'."\n";
Line 913  LISTJAVASCRIPT Line 1032  LISTJAVASCRIPT
  ' students checked for '.$submissions.')</span><br />';   ' students checked for '.$submissions.')</span><br />';
  }   }
     } elsif ($ctr == 1) {      } elsif ($ctr == 1) {
  $gradeTable =~ s/type=checkbox/type=checkbox checked/;   $gradeTable =~ s/type="checkbox"/type="checkbox" checked="checked"/;
     }      }
     $gradeTable.=&show_grading_menu_form($symb);      $gradeTable.=&show_grading_menu_form($symb);
     $request->print($gradeTable);      $request->print($gradeTable);
Line 1365  INNERJS Line 1484  INNERJS
   
     pDoc.write("<form action=\\"inactive\\" name=\\"msgcenter\\">");      pDoc.write("<form action=\\"inactive\\" name=\\"msgcenter\\">");
     pDoc.write("<input value=\\""+usrctr+"\\" name=\\"usrctr\\" type=\\"hidden\\">");      pDoc.write("<input value=\\""+usrctr+"\\" name=\\"usrctr\\" type=\\"hidden\\">");
     pDoc.write("<h3><span class=\\"LC_info\\">&nbsp;Compose Message for \"+fullname+\"</span></h3><br /><br />");      pDoc.write("<h3><span class=\\"LC_info\\">&nbsp;Compose Message for \"+fullname+\"<\\/span><\\/h3><br /><br />");
   
     pDoc.write("<table border=0 width=100%><tr><td bgcolor=\\"#777777\\">");      pDoc.write("<table border=0 width=100%><tr><td bgcolor=\\"#777777\\">");
     pDoc.write("<table border=0 width=100%><tr bgcolor=\\"#ddffff\\">");      pDoc.write("<table border=0 width=100%><tr bgcolor=\\"#ddffff\\">");
     pDoc.write("<td><b>Type</b></td><td><b>Include</b></td><td><b>Message</td></tr>");      pDoc.write("<td><b>Type<\\/b><\\/td><td><b>Include<\\/b><\\/td><td><b>Message<\\/td><\\/tr>");
 }  }
     function displaySubject(msg,shwsel) {      function displaySubject(msg,shwsel) {
     pDoc = pWin.document;      pDoc = pWin.document;
     pDoc.write("<tr bgcolor=\\"#ffffdd\\">");      pDoc.write("<tr bgcolor=\\"#ffffdd\\">");
     pDoc.write("<td>Subject</td>");      pDoc.write("<td>Subject<\\/td>");
     pDoc.write("<td align=\\"center\\"><input name=\\"subchk\\" type=\\"checkbox\\"" +shwsel+"></td>");      pDoc.write("<td align=\\"center\\"><input name=\\"subchk\\" type=\\"checkbox\\"" +shwsel+"><\\/td>");
     pDoc.write("<td><input name=\\"msgsub\\" type=\\"text\\" value=\\""+msg+"\\"size=\\"60\\" maxlength=\\"80\\"></td></tr>");      pDoc.write("<td><input name=\\"msgsub\\" type=\\"text\\" value=\\""+msg+"\\"size=\\"60\\" maxlength=\\"80\\"><\\/td><\\/tr>");
 }  }
   
   function displaySavedMsg(ctr,msg,shwsel) {    function displaySavedMsg(ctr,msg,shwsel) {
     pDoc = pWin.document;      pDoc = pWin.document;
     pDoc.write("<tr bgcolor=\\"#ffffdd\\">");      pDoc.write("<tr bgcolor=\\"#ffffdd\\">");
     pDoc.write("<td align=\\"center\\">"+ctr+"</td>");      pDoc.write("<td align=\\"center\\">"+ctr+"<\\/td>");
     pDoc.write("<td align=\\"center\\"><input name=\\"msgn"+ctr+"\\" type=\\"checkbox\\"" +shwsel+"></td>");      pDoc.write("<td align=\\"center\\"><input name=\\"msgn"+ctr+"\\" type=\\"checkbox\\"" +shwsel+"><\\/td>");
     pDoc.write("<td><textarea name=\\"msg"+ctr+"\\" cols=\\"60\\" rows=\\"3\\">"+msg+"</textarea></td></tr>");      pDoc.write("<td><textarea name=\\"msg"+ctr+"\\" cols=\\"60\\" rows=\\"3\\">"+msg+"<\\/textarea><\\/td><\\/tr>");
 }  }
   
   function newMsg(newmsg,shwsel) {    function newMsg(newmsg,shwsel) {
     pDoc = pWin.document;      pDoc = pWin.document;
     pDoc.write("<tr bgcolor=\\"#ffffdd\\">");      pDoc.write("<tr bgcolor=\\"#ffffdd\\">");
     pDoc.write("<td align=\\"center\\">New</td>");      pDoc.write("<td align=\\"center\\">New<\\/td>");
     pDoc.write("<td align=\\"center\\"><input name=\\"newmsgchk\\" type=\\"checkbox\\"" +shwsel+"></td>");      pDoc.write("<td align=\\"center\\"><input name=\\"newmsgchk\\" type=\\"checkbox\\"" +shwsel+"><\\/td>");
     pDoc.write("<td><textarea name=\\"newmsg\\" cols=\\"60\\" rows=\\"3\\" onchange=\\"javascript:this.form.newmsgchk.checked=true\\" >"+newmsg+"</textarea></td></tr>");      pDoc.write("<td><textarea name=\\"newmsg\\" cols=\\"60\\" rows=\\"3\\" onchange=\\"javascript:this.form.newmsgchk.checked=true\\" >"+newmsg+"<\\/textarea><\\/td><\\/tr>");
 }  }
   
   function msgTail() {    function msgTail() {
     pDoc = pWin.document;      pDoc = pWin.document;
     pDoc.write("</table>");      pDoc.write("<\\/table>");
     pDoc.write("</td></tr></table>&nbsp;");      pDoc.write("<\\/td><\\/tr><\\/table>&nbsp;");
     pDoc.write("<input type=\\"button\\" value=\\"Save\\" onClick=\\"javascript:checkInput()\\">&nbsp;&nbsp;");      pDoc.write("<input type=\\"button\\" value=\\"Save\\" onClick=\\"javascript:checkInput()\\">&nbsp;&nbsp;");
     pDoc.write("<input type=\\"button\\" value=\\"Cancel\\" onClick=\\"self.close()\\"><br /><br />");      pDoc.write("<input type=\\"button\\" value=\\"Cancel\\" onClick=\\"self.close()\\"><br /><br />");
     pDoc.write("</form>");      pDoc.write("<\\/form>");
     pDoc.write('$end_page_msg_central');      pDoc.write('$end_page_msg_central');
     pDoc.close();      pDoc.close();
 }  }
Line 1450  INNERJS Line 1569  INNERJS
     hDoc.$docopen;      hDoc.$docopen;
     hDoc.write('$start_page_highlight_central');      hDoc.write('$start_page_highlight_central');
     hDoc.write("<form action=\\"inactive\\" name=\\"hlCenter\\">");      hDoc.write("<form action=\\"inactive\\" name=\\"hlCenter\\">");
     hDoc.write("<h3><span class=\\"LC_info\\">&nbsp;Keyword Highlight Options</span></h3><br /><br />");      hDoc.write("<h3><span class=\\"LC_info\\">&nbsp;Keyword Highlight Options<\\/span><\\/h3><br /><br />");
   
     hDoc.write("<table border=0 width=100%><tr><td bgcolor=\\"#777777\\">");      hDoc.write("<table border=0 width=100%><tr><td bgcolor=\\"#777777\\">");
     hDoc.write("<table border=0 width=100%><tr bgcolor=\\"#ddffff\\">");      hDoc.write("<table border=0 width=100%><tr bgcolor=\\"#ddffff\\">");
     hDoc.write("<td><b>Text Color</b></td><td><b>Font Size</b></td><td><b>Font Style</td></tr>");      hDoc.write("<td><b>Text Color<\\/b><\\/td><td><b>Font Size<\\/b><\\/td><td><b>Font Style<\\/td><\\/tr>");
   }    }
   
   function highlightbody(clrval,clrtxt,clrsel,szval,sztxt,szsel,syval,sytxt,sysel) {     function highlightbody(clrval,clrtxt,clrsel,szval,sztxt,szsel,syval,sytxt,sysel) { 
     var hDoc = hwdWin.document;      var hDoc = hwdWin.document;
     hDoc.write("<tr bgcolor=\\"#ffffdd\\">");      hDoc.write("<tr bgcolor=\\"#ffffdd\\">");
     hDoc.write("<td align=\\"left\\">");      hDoc.write("<td align=\\"left\\">");
     hDoc.write("<input name=\\"kwdclr\\" type=\\"radio\\" value=\\""+clrval+"\\" "+clrsel+">&nbsp;"+clrtxt+"</td>");      hDoc.write("<input name=\\"kwdclr\\" type=\\"radio\\" value=\\""+clrval+"\\" "+clrsel+">&nbsp;"+clrtxt+"<\\/td>");
     hDoc.write("<td align=\\"left\\">");      hDoc.write("<td align=\\"left\\">");
     hDoc.write("<input name=\\"kwdsize\\" type=\\"radio\\" value=\\""+szval+"\\" "+szsel+">&nbsp;"+sztxt+"</td>");      hDoc.write("<input name=\\"kwdsize\\" type=\\"radio\\" value=\\""+szval+"\\" "+szsel+">&nbsp;"+sztxt+"<\\/td>");
     hDoc.write("<td align=\\"left\\">");      hDoc.write("<td align=\\"left\\">");
     hDoc.write("<input name=\\"kwdstyle\\" type=\\"radio\\" value=\\""+syval+"\\" "+sysel+">&nbsp;"+sytxt+"</td>");      hDoc.write("<input name=\\"kwdstyle\\" type=\\"radio\\" value=\\""+syval+"\\" "+sysel+">&nbsp;"+sytxt+"<\\/td>");
     hDoc.write("</tr>");      hDoc.write("<\\/tr>");
   }    }
   
   function highlightend() {     function highlightend() { 
     var hDoc = hwdWin.document;      var hDoc = hwdWin.document;
     hDoc.write("</table>");      hDoc.write("<\\/table>");
     hDoc.write("</td></tr></table>&nbsp;");      hDoc.write("<\\/td><\\/tr><\\/table>&nbsp;");
     hDoc.write("<input type=\\"button\\" value=\\"Save\\" onClick=\\"javascript:updateChoice(1)\\">&nbsp;&nbsp;");      hDoc.write("<input type=\\"button\\" value=\\"Save\\" onClick=\\"javascript:updateChoice(1)\\">&nbsp;&nbsp;");
     hDoc.write("<input type=\\"button\\" value=\\"Cancel\\" onClick=\\"self.close()\\"><br /><br />");      hDoc.write("<input type=\\"button\\" value=\\"Cancel\\" onClick=\\"self.close()\\"><br /><br />");
     hDoc.write("</form>");      hDoc.write("<\\/form>");
     hDoc.write('$end_page_highlight_central');      hDoc.write('$end_page_highlight_central');
     hDoc.close();      hDoc.close();
   }    }
Line 1500  sub gradeBox { Line 1619  sub gradeBox {
  '" src="'.$request->dir_config('lonIconsURL').   '" src="'.$request->dir_config('lonIconsURL').
  '/check.gif" height="16" border="0" />';   '/check.gif" height="16" border="0" />';
     my $wgt    = &Apache::lonnet::EXT('resource.'.$partid.'.weight',$symb,$udom,$uname);      my $wgt    = &Apache::lonnet::EXT('resource.'.$partid.'.weight',$symb,$udom,$uname);
     my $wgtmsg = ($wgt > 0 ? '(problem weight)' :       my $wgtmsg = ($wgt > 0) ? &mt('(problem weight)') 
   '<span class="LC_info">problem weight assigned by computer</span>');                             : '<span class="LC_info">'.&mt('problem weight assigned by computer').'</span>';
     $wgt       = ($wgt > 0 ? $wgt : '1');      $wgt       = ($wgt > 0 ? $wgt : '1');
     my $score  = ($$record{'resource.'.$partid.'.awarded'} eq '' ?      my $score  = ($$record{'resource.'.$partid.'.awarded'} eq '' ?
   '' : &compute_points($$record{'resource.'.$partid.'.awarded'},$wgt));    '' : &compute_points($$record{'resource.'.$partid.'.awarded'},$wgt));
     my $result='<input type="hidden" name="WGT'.$counter.'_'.$partid.'" value="'.$wgt.'" />'."\n";      my $result='<input type="hidden" name="WGT'.$counter.'_'.$partid.'" value="'.$wgt.'" />'."\n";
     my $display_part=&get_display_part($partid,$symb);      my $display_part= &get_display_part($partid,$symb);
     my %last_resets = &get_last_resets($symb,$env{'request.course.id'},      my %last_resets = &get_last_resets($symb,$env{'request.course.id'},
        [$partid]);         [$partid]);
     my $aggtries = $$record{'resource.'.$partid.'.tries'};      my $aggtries = $$record{'resource.'.$partid.'.tries'};
Line 1588  sub handback_box { Line 1707  sub handback_box {
     '<span class="LC_filename">'.$file_disp.'</span>');      '<span class="LC_filename">'.$file_disp.'</span>');
            $result.='<input type="file"   name="'.$prefix.'returndoc'.$file_counter.'" />'."\n";             $result.='<input type="file"   name="'.$prefix.'returndoc'.$file_counter.'" />'."\n";
            $result.='<input type="hidden" name="'.$prefix.'origdoc'.$file_counter.'" value="'.$file.'" /><br />';             $result.='<input type="hidden" name="'.$prefix.'origdoc'.$file_counter.'" value="'.$file.'" /><br />';
            $result.='(File will be uploaded when you click on Save & Next below.)<br />';             $result.='(File will be uploaded when you click on Save &amp; Next below.)<br />';
            $file_counter++;             $file_counter++;
     }      }
  }   }
Line 1624  sub show_problem { Line 1743  sub show_problem {
  $companswer=~s|</form>||g;   $companswer=~s|</form>||g;
  $companswer=~s|name="submit"|name="would_have_been_submit"|g;   $companswer=~s|name="submit"|name="would_have_been_submit"|g;
     }      }
     my $result.='<table border="0" width="100%"><tr><td bgcolor="#777777">';      $rendered=
     $result.='<table border="0" width="100%">';   '<div class="LC_grade_show_problem_header">'.
     if ($viewon) {   &mt('View of the problem').
  $result.='<tr><td bgcolor="#e6ffff"><b> ';   '</div><div class="LC_grade_show_problem_problem">'.
  if ($mode eq 'both' or $mode eq 'text') {   $rendered.
     $result.='View of the problem - ';   '</div>';
  } else {      $companswer=
     $result.='Correct answer: ';   '<div class="LC_grade_show_problem_header">'.
  }   &mt('Correct answer').
  $result.=$env{'form.fullname'}.'</b></td></tr>';   '</div><div class="LC_grade_show_problem_problem">'.
     }   $companswer.
    '</div>';
       my $result;
     if ($mode eq 'both') {      if ($mode eq 'both') {
  $result.='<tr><td bgcolor="#ffffff">'.$rendered.'<br />';   $result=$rendered.$companswer;
  $result.='<b>Correct answer:</b><br />'.$companswer;  
     } elsif ($mode eq 'text') {      } elsif ($mode eq 'text') {
  $result.='<tr><td bgcolor="#ffffff">'.$rendered;   $result=$rendered;
     } elsif ($mode eq 'answer') {      } elsif ($mode eq 'answer') {
  $result.='<tr><td bgcolor="#ffffff">'.$companswer;   $result=$companswer;
     }      }
     $result.='</td></tr></table>';      $result='<div class="LC_grade_show_problem">'.$result.'</div>';
     $result.='</td></tr></table><br />';  
     return $result;      return $result;
 }  }
   
Line 1701  sub build_section_inputs { Line 1820  sub build_section_inputs {
 # --------------------------- show submissions of a student, option to grade   # --------------------------- show submissions of a student, option to grade 
 sub submission {  sub submission {
     my ($request,$counter,$total) = @_;      my ($request,$counter,$total) = @_;
   
     my ($uname,$udom)     = ($env{'form.student'},$env{'form.userdom'});      my ($uname,$udom)     = ($env{'form.student'},$env{'form.userdom'});
     $udom = ($udom eq '' ? $env{'user.domain'} : $udom); #has form.userdom changed for a student?      $udom = ($udom eq '' ? $env{'user.domain'} : $udom); #has form.userdom changed for a student?
     my $usec = &Apache::lonnet::getsection($udom,$uname,$env{'request.course.id'});      my $usec = &Apache::lonnet::getsection($udom,$uname,$env{'request.course.id'});
Line 1738  sub submission { Line 1856  sub submission {
  $request->print('<h3>&nbsp;<span class="LC_info">Submission Record</span></h3>'."\n".   $request->print('<h3>&nbsp;<span class="LC_info">Submission Record</span></h3>'."\n".
  '<h4>&nbsp;<b>Resource: </b>'.$env{'form.probTitle'}.'</h4>'."\n");   '<h4>&nbsp;<b>Resource: </b>'.$env{'form.probTitle'}.'</h4>'."\n");
   
  if ($env{'form.handgrade'} eq 'no') {  
     my $checkMark='<br /><br />&nbsp;<b>Note:</b> Part(s) graded correct by the computer is marked with a '.  
  $checkIcon.' symbol.'."\n";  
     $request->print($checkMark);  
  }  
   
  # option to display problem, only once else it cause problems    # option to display problem, only once else it cause problems 
         # with the form later since the problem has a form.          # with the form later since the problem has a form.
  if ($env{'form.vProb'} eq 'yes' or $env{'form.vAns'} eq 'yes') {   if ($env{'form.vProb'} eq 'yes' or $env{'form.vAns'} eq 'yes') {
Line 1777  sub submission { Line 1889  sub submission {
     $env{'form.savemsgN'} = $keyhash{$symb.'_savemsgN'} ne '' ? $keyhash{$symb.'_savemsgN'} : '0';      $env{'form.savemsgN'} = $keyhash{$symb.'_savemsgN'} ne '' ? $keyhash{$symb.'_savemsgN'} : '0';
  }   }
  my $overRideScore = $env{'form.overRideScore'} eq '' ? 'no' : $env{'form.overRideScore'};   my $overRideScore = $env{'form.overRideScore'} eq '' ? 'no' : $env{'form.overRideScore'};
    my $stu_status = join(':',&Apache::loncommon::get_env_multiple('form.Status'));
  $request->print('<form action="/adm/grades" method="post" name="SCORE" enctype="multipart/form-data">'."\n".   $request->print('<form action="/adm/grades" method="post" name="SCORE" enctype="multipart/form-data">'."\n".
  '<input type="hidden" name="command"    value="handgrade" />'."\n".   '<input type="hidden" name="command"    value="handgrade" />'."\n".
  '<input type="hidden" name="saveState"  value="'.$env{'form.saveState'}.'" />'."\n".   '<input type="hidden" name="saveState"  value="'.$env{'form.saveState'}.'" />'."\n".
  '<input type="hidden" name="Status"     value="'.$env{'form.Status'}.'" />'."\n".   '<input type="hidden" name="Status"     value="'.$stu_status.'" />'."\n".
  '<input type="hidden" name="overRideScore" value="'.$overRideScore.'" />'."\n".   '<input type="hidden" name="overRideScore" value="'.$overRideScore.'" />'."\n".
  '<input type="hidden" name="probTitle"  value="'.$env{'form.probTitle'}.'" />'."\n".   '<input type="hidden" name="probTitle"  value="'.$env{'form.probTitle'}.'" />'."\n".
  '<input type="hidden" name="refresh"    value="off" />'."\n".   '<input type="hidden" name="refresh"    value="off" />'."\n".
Line 1844  KEYWORDS Line 1957  KEYWORDS
     }      }
   
 # This is where output for one specific student would start  # This is where output for one specific student would start
     my $bgcolor='#DDEEDD';      my $add_class = ($counter%2) ? 'LC_grade_show_user_odd_row' : '';
     if (int($counter/2) eq $counter) { $bgcolor='#DDDDEE'; }  
     $request->print("\n\n".      $request->print("\n\n".
                     '<p><table border="2"><tr><th bgcolor="'.$bgcolor.'">'.$env{'form.fullname'}.'</th></tr><tr><td bgcolor="'.$bgcolor.'">');                      '<div class="LC_grade_show_user '.$add_class.'">'.
       '<div class="LC_grade_user_name">'.&nameUserString(undef,$env{'form.fullname'},$uname,$udom).'</div>'.
       '<div class="LC_grade_show_user_body">'."\n");
   
     if ($env{'form.vProb'} eq 'all' or $env{'form.vAns'} eq 'all') {      if ($env{'form.vProb'} eq 'all' or $env{'form.vAns'} eq 'all') {
  my $mode;   my $mode;
Line 1859  KEYWORDS Line 1973  KEYWORDS
     $mode='answer';      $mode='answer';
  }   }
  &Apache::lonxml::clear_problem_counter();   &Apache::lonxml::clear_problem_counter();
  $request->print(&show_problem($request,$symb,$uname,$udom,1,1,$mode));   $request->print(&show_problem($request,$symb,$uname,$udom,1,1,$mode,{'request.prefix' => 'ctr'.$counter}));
     }      }
   
     my %record = &Apache::lonnet::restore($symb,$env{'request.course.id'},$udom,$uname);      my %record = &Apache::lonnet::restore($symb,$env{'request.course.id'},$udom,$uname);
Line 1867  KEYWORDS Line 1981  KEYWORDS
   
     # Display student info      # Display student info
     $request->print(($counter == 0 ? '' : '<br />'));      $request->print(($counter == 0 ? '' : '<br />'));
     my $result='<table border="0" width="100%"><tr><td bgcolor="#777777">'."\n".      my $result='<div class="LC_grade_submissions">';
  '<table border="0" width="100%"><tr bgcolor="#edffff"><td>'."\n";      
       $result.='<div class="LC_grade_submissions_header">';
     $result.='<b>Fullname: </b>'.&nameUserString(undef,$env{'form.fullname'},$uname,$udom).'<br />'."\n";      $result.= &mt('Submissions');
     $result.='<input type="hidden" name="name'.$counter.      $result.='<input type="hidden" name="name'.$counter.
  '" value="'.$env{'form.fullname'}.'" />'."\n";   '" value="'.$env{'form.fullname'}.'" />'."\n";
       if ($env{'form.handgrade'} eq 'no') {
    $result.='<span class="LC_grade_check_note">'.
       &mt('Part(s) graded correct by the computer is marked with a [_1] symbol.',$checkIcon)."</span>\n";
   
       }
   
   
   
     # If any part of the problem is an essay-response (handgraded), then check for collaborators      # If any part of the problem is an essay-response (handgraded), then check for collaborators
     my @col_fullnames;      my $fullname;
     my ($classlist,$fullname);      my $col_fullnames = [];
     if ($env{'form.handgrade'} eq 'yes') {      if ($env{'form.handgrade'} eq 'yes') {
  ($classlist,undef,$fullname) = &getclasslist('all','0');   (my $sub_result,$fullname,$col_fullnames)=
  for (keys (%$handgrade)) {      &check_collaborators($symb,$uname,$udom,\%record,$handgrade,
     my $ncol = &Apache::lonnet::EXT('resource.'.$_.   $counter);
     '.maxcollaborators',   $result.=$sub_result;
                                             $symb,$udom,$uname);  
     next if ($ncol <= 0);  
             s/\_/\./g;  
             next if ($record{'resource.'.$_.'.collaborators'} eq '');  
             my @goodcollaborators = ();  
             my @badcollaborators  = ();  
     foreach (split(/,?\s+/,$record{'resource.'.$_.'.collaborators'})) {   
  $_ =~ s/[\$\^\(\)]//g;  
  next if ($_ eq '');  
  my ($co_name,$co_dom) = split /\@|:/,$_;  
  $co_dom = $udom if (! defined($co_dom) || $co_dom =~ /^domain$/i);  
  next if ($co_name eq $uname && $co_dom eq $udom);  
  # Doing this grep allows 'fuzzy' specification  
  my @Matches = grep /^$co_name:$co_dom$/i,keys %$classlist;  
  if (! scalar(@Matches)) {  
     push @badcollaborators,$_;  
  } else {  
     push @goodcollaborators, @Matches;  
  }  
     }  
             if (scalar(@goodcollaborators) != 0) {  
                 $result.='<b>Collaborators: </b>';  
                 foreach (@goodcollaborators) {  
     my ($lastname,$givenn) = split(/,/,$$fullname{$_});  
     push @col_fullnames, $givenn.' '.$lastname;  
     $result.=$$fullname{$_}.'&nbsp; &nbsp; &nbsp;';  
  }  
                 $result.='<br />'."\n";  
  my ($part)=split(/\./,$_);  
  $result.='<input type="hidden" name="collaborator'.$counter.  
     '" value="'.$part.':'.(join ':',@goodcollaborators).'" />'.  
     "\n";  
     }  
     if (scalar(@badcollaborators) > 0) {  
  $result.='<table border="0"><tr bgcolor="#ffbbbb"><td>';  
  $result.='This student has submitted ';  
  $result.=(scalar(@badcollaborators) == 1) ? 'an invalid collaborator' : 'invalid collaborators';  
  $result .= ': '.join(', ',@badcollaborators);  
  $result .= '</td></tr></table>';  
     }           
     if (scalar(@badcollaborators > $ncol)) {  
  $result .= '<table border="0"><tr bgcolor="#ffbbbb"><td>';  
  $result .= 'This student has submitted too many '.  
     'collaborators.  Maximum is '.$ncol.'.';  
  $result .= '</td></tr></table>';  
     }  
  }  
     }      }
     $request->print($result."\n");      $request->print($result."\n");
       $request->print('</div>'."\n");
     # print student answer/submission      # print student answer/submission
     # Options are (1) Handgaded submission only      # Options are (1) Handgaded submission only
     #             (2) Last submission, includes submission that is not handgraded       #             (2) Last submission, includes submission that is not handgraded 
Line 1940  KEYWORDS Line 2014  KEYWORDS
     #             (4) The whole record for this student      #             (4) The whole record for this student
     if ($env{'form.lastSub'} =~ /^(lastonly|hdgrade)$/) {      if ($env{'form.lastSub'} =~ /^(lastonly|hdgrade)$/) {
  my ($string,$timestamp)= &get_last_submission(\%record);   my ($string,$timestamp)= &get_last_submission(\%record);
  my $lastsubonly=''.  
     ($$timestamp eq '' ? '' : '<b>Date Submitted:</b> '.   my $lastsubonly;
      $$timestamp)."</td></tr>\n";  
  if ($$timestamp eq '') {   if ($$timestamp eq '') {
     $lastsubonly.='<tr><td bgcolor="#ffffe6">'.$$string[0];       $lastsubonly.='<div class="LC_grade_submissions_body">'.$$string[0].'</div>'; 
  } else {   } else {
       $lastsubonly = '<div class="LC_grade_submissions_body"> <b>Date Submitted:</b> '.$$timestamp."\n";
   
     my %seenparts;      my %seenparts;
     my @part_response_id = &flatten_responseType($responseType);      my @part_response_id = &flatten_responseType($responseType);
     foreach my $part (@part_response_id) {      foreach my $part (@part_response_id) {
Line 1968  KEYWORDS Line 2044  KEYWORDS
  }   }
  my $responsetype = $responseType->{$partid}->{$respid};   my $responsetype = $responseType->{$partid}->{$respid};
  if (!exists($record{"resource.$partid.$respid.submission"})) {   if (!exists($record{"resource.$partid.$respid.submission"})) {
     $lastsubonly.='<tr><td bgcolor="#ffffe6"><b>Part:</b> '.      $lastsubonly.="\n".'<div class="LC_grade_submission_part"><b>Part:</b> '.
  $display_part.' <span class="LC_internal_info">( ID '.$respid.   $display_part.' <span class="LC_internal_info">( ID '.$respid.
  ' )</span>&nbsp; &nbsp;'.   ' )</span>&nbsp; &nbsp;'.
  '<span class="LC_warning">Nothing submitted - no attempts</span><br /><br />';   '<span class="LC_warning">'.&mt('Nothing submitted - no attempts').'</span><br /><br /></div>';
     next;      next;
  }   }
  foreach (@$string) {   foreach my $submission (@$string) {
     my ($partid,$respid) = /^resource\.([^\.]*)\.([^\.]*)\.submission/;      my ($partid,$respid) = ($submission =~ /^resource\.([^\.]*)\.([^\.]*)\.submission/);
     if (join('_',@{$part}) ne ($partid.'_'.$respid)) { next; }      if (join('_',@{$part}) ne ($partid.'_'.$respid)) { next; }
     my ($ressub,$subval) = split(/:/,$_,2);      my ($ressub,$subval) = split(/:/,$submission,2);
     # Similarity check      # Similarity check
     my $similar='';      my $similar='';
     if($env{'form.checkPlag'}){      if($env{'form.checkPlag'}){
Line 2007  KEYWORDS Line 2083  KEYWORDS
  ($env{'form.lastSub'} eq 'hdgrade' &&    ($env{'form.lastSub'} eq 'hdgrade' && 
  $$handgrade{$$part[0].'_'.$$part[1]} eq 'yes')) {   $$handgrade{$$part[0].'_'.$$part[1]} eq 'yes')) {
  my $display_part=&get_display_part($partid,$symb);   my $display_part=&get_display_part($partid,$symb);
  $lastsubonly.='<tr><td bgcolor="#ffffe6"><b>Part:</b> '.   $lastsubonly.='<div class="LC_grade_submission_part"><b>Part:</b> '.
     $display_part.' <span class="LC_internal_info">( ID '.$respid.      $display_part.' <span class="LC_internal_info">( ID '.$respid.
     ' )</span>&nbsp; &nbsp;';      ' )</span>&nbsp; &nbsp;';
  my $files=&get_submitted_files($udom,$uname,$partid,$respid,\%record);   my $files=&get_submitted_files($udom,$uname,$partid,$respid,\%record);
  if (@$files) {   if (@$files) {
     $lastsubonly.='<br /><span class="LC_warning">Like all files provided by users, this file may contain virusses</span><br />';      $lastsubonly.='<br /><span class="LC_warning">'.&mt('Like all files provided by users, this file may contain virusses').'</span><br />';
     my $file_counter = 0;      my $file_counter = 0;
     foreach my $file (@$files) {      foreach my $file (@$files) {
         $file_counter ++;          $file_counter++;
  &Apache::lonnet::allowuploaded('/adm/grades',$file);   &Apache::lonnet::allowuploaded('/adm/grades',$file);
  $lastsubonly.='<br /><a href="'.$file.'?rawmode=1" target="lonGRDs"><img src="'.&Apache::loncommon::icon($file).'" border=0"> '.$file.'</a>';   $lastsubonly.='<br /><a href="'.$file.'?rawmode=1" target="lonGRDs"><img src="'.&Apache::loncommon::icon($file).'" border=0"> '.$file.'</a>';
     }      }
     $lastsubonly.='<br />';      $lastsubonly.='<br />';
  }   }
  $lastsubonly.='<b>Submitted Answer: </b>'.   $lastsubonly.='<b>'.&mt('Submitted Answer:').' </b>'.
     &cleanRecord($subval,$responsetype,$symb,$partid,      &cleanRecord($subval,$responsetype,$symb,$partid,
  $respid,\%record,$order);   $respid,\%record,$order);
  if ($similar) {$lastsubonly.="<br /><br />$similar\n";}   if ($similar) {$lastsubonly.="<br /><br />$similar\n";}
    $lastsubonly.='</div>';
     }      }
  }   }
     }      }
       $lastsubonly.='</div>'."\n";
  }   }
  $lastsubonly.='</td></tr><tr bgcolor="#ffffff"><td>'."\n";  
  $request->print($lastsubonly);   $request->print($lastsubonly);
     } elsif ($env{'form.lastSub'} eq 'datesub') {     } elsif ($env{'form.lastSub'} eq 'datesub') {
  my (undef,$responseType,undef,$parts) = &showResourceInfo($symb);   my (undef,$responseType,undef,$parts) = &showResourceInfo($symb);
  $request->print(&displaySubByDates($symb,\%record,$parts,$responseType,$checkIcon,$uname,$udom));   $request->print(&displaySubByDates($symb,\%record,$parts,$responseType,$checkIcon,$uname,$udom));
     } elsif ($env{'form.lastSub'} =~ /^(last|all)$/) {      } elsif ($env{'form.lastSub'} =~ /^(last|all)$/) {
Line 2043  KEYWORDS Line 2120  KEYWORDS
   
     $request->print('<input type="hidden" name="unamedom'.$counter.'" value="'.$uname.':'      $request->print('<input type="hidden" name="unamedom'.$counter.'" value="'.$uname.':'
  .$udom.'" />'."\n");   .$udom.'" />'."\n");
       
     # return if view submission with no grading option      # return if view submission with no grading option
     if ($env{'form.showgrading'} eq '' || (!&canmodify($usec))) {      if ($env{'form.showgrading'} eq '' || (!&canmodify($usec))) {
  my $toGrade.='<input type="button" value="Grade Student" '.   my $toGrade.='<input type="button" value="Grade Student" '.
     'onClick="javascript:checksubmit(this.form,\'Grade Student\',\''      'onClick="javascript:checksubmit(this.form,\'Grade Student\',\''
     .$counter.'\');" target="_self" /> &nbsp;'."\n" if (&canmodify($usec));      .$counter.'\');" target="_self" /> &nbsp;'."\n" if (&canmodify($usec));
  $toGrade.='</td></tr></table></td></tr></table>'."\n";   $toGrade.='</div>'."\n";
  if (($env{'form.command'} eq 'submission') ||    if (($env{'form.command'} eq 'submission') || 
     ($env{'form.command'} eq 'processGroup' && $counter == $total)) {      ($env{'form.command'} eq 'processGroup' && $counter == $total)) {
     $toGrade.='</form>'.&show_grading_menu_form($symb);       $toGrade.='</form>'.&show_grading_menu_form($symb); 
Line 2057  KEYWORDS Line 2133  KEYWORDS
  $request->print($toGrade);   $request->print($toGrade);
  return;   return;
     } else {      } else {
  $request->print('</td></tr></table></td></tr></table>'."\n");   $request->print('</div>'."\n");
     }      }
   
     # essay grading message center      # essay grading message center
     if ($env{'form.handgrade'} eq 'yes') {      if ($env{'form.handgrade'} eq 'yes') {
    my $result='<div class="LC_grade_message_center">';
       
    $result.='<div class="LC_grade_message_center_header">'.
       &mt('Send Message').'</div><div class="LC_grade_message_center_body">';
  my ($lastname,$givenn) = split(/,/,$env{'form.fullname'});   my ($lastname,$givenn) = split(/,/,$env{'form.fullname'});
  my $msgfor = $givenn.' '.$lastname;   my $msgfor = $givenn.' '.$lastname;
  if (scalar(@col_fullnames) > 0) {   if (scalar(@$col_fullnames) > 0) {
     my $lastone = pop @col_fullnames;      my $lastone = pop(@$col_fullnames);
     $msgfor .= ', '.(join ', ',@col_fullnames).' and '.$lastone.'.';      $msgfor .= ', '.(join ', ',@$col_fullnames).' and '.$lastone.'.';
  }   }
  $msgfor =~ s/\'/\\'/g; #' stupid emacs - no! javascript   $msgfor =~ s/\'/\\'/g; #' stupid emacs - no! javascript
  $result='<input type="hidden" name="includemsg'.$counter.'" value="" />'."\n".   $result.='<input type="hidden" name="includemsg'.$counter.'" value="" />'."\n".
     '<input type="hidden" name="newmsg'.$counter.'" value="" />'."\n";      '<input type="hidden" name="newmsg'.$counter.'" value="" />'."\n";
  $result.='&nbsp;<a href="javascript:msgCenter(document.SCORE,'.$counter.   $result.='&nbsp;<a href="javascript:msgCenter(document.SCORE,'.$counter.
     ',\''.$msgfor.'\');" target="_self">'.      ',\''.$msgfor.'\');" target="_self">'.
     &mt('Compose message to student').(scalar(@col_fullnames) >= 1 ? 's' : '').'</a><label> ('.      &mt('Compose message to student').(scalar(@$col_fullnames) >= 1 ? 's' : '').'</a><label> ('.
     &mt('incl. grades').' <input type="checkbox" name="withgrades'.$counter.'" /></label>)'.      &mt('incl. grades').' <input type="checkbox" name="withgrades'.$counter.'" /></label>)'.
     '<img src="'.$request->dir_config('lonIconsURL').      '<img src="'.$request->dir_config('lonIconsURL').
     '/mailbkgrd.gif" width="14" height="10" name="mailicon'.$counter.'" />'."\n".      '/mailbkgrd.gif" width="14" height="10" name="mailicon'.$counter.'" />'."\n".
     '<br />&nbsp;('.      '<br />&nbsp;('.
     &mt('Message will be sent when you click on Save & Next below.').")\n";      &mt('Message will be sent when you click on Save &amp; Next below.').")\n";
    $result.='</div></div>';
  $request->print($result);   $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 %seen = ();
     my @partlist;      my @partlist;
     my @gradePartRespid;      my @gradePartRespid;
     my @part_response_id = &flatten_responseType($responseType);      my @part_response_id = &flatten_responseType($responseType);
       $request->print('<div class="LC_grade_assign">'.
       
       '<div class="LC_grade_assign_header">'.
       &mt('Assign Grades').'</div>'.
       '<div class="LC_grade_assign_body">');
     foreach my $part_response_id (@part_response_id) {      foreach my $part_response_id (@part_response_id) {
     my ($partid,$respid) = @{ $part_response_id };      my ($partid,$respid) = @{ $part_response_id };
  my $part_resp = join('_',@{ $part_response_id });   my $part_resp = join('_',@{ $part_response_id });
Line 2107  KEYWORDS Line 2183  KEYWORDS
  push @gradePartRespid,$partid.'.'.$respid;   push @gradePartRespid,$partid.'.'.$respid;
  $request->print(&gradeBox($request,$symb,$uname,$udom,$counter,$partid,\%record));   $request->print(&gradeBox($request,$symb,$uname,$udom,$counter,$partid,\%record));
     }      }
       $request->print('</div></div>');
   
       $request->print('<div class="LC_grade_info_links">');
       if ($perm{'vgr'}) {
    $request->print(
       &Apache::loncommon::track_student_link(&mt('View recent activity'),
      $uname,$udom,'check'));
       }
       if ($perm{'opa'}) {
    $request->print(
       &Apache::loncommon::pprmlink(&mt('Set/Change parameters'),
    $uname,$udom,$symb,'check'));
       }
       $request->print('</div>');
   
     $result='<input type="hidden" name="partlist'.$counter.      $result='<input type="hidden" name="partlist'.$counter.
  '" value="'.(join ":",@partlist).'" />'."\n";   '" value="'.(join ":",@partlist).'" />'."\n";
     $result.='<input type="hidden" name="gradePartRespid'.      $result.='<input type="hidden" name="gradePartRespid'.
Line 2117  KEYWORDS Line 2208  KEYWORDS
     $partlist[$ctr].'" />'."\n";      $partlist[$ctr].'" />'."\n";
  $ctr++;   $ctr++;
     }      }
     $request->print($result.'</td></tr></table></td></tr></table>'."\n");      $request->print($result.''."\n");
   
 # Done with printing info for one student  # Done with printing info for one student
   
     $request->print('</td></tr></table></p>');      $request->print('</div>');#LC_grade_show_user_body
       $request->print('</div>');#LC_grade_show_user
   
   
     # print end of form      # print end of form
Line 2151  KEYWORDS Line 2243  KEYWORDS
     return '';      return '';
 }  }
   
   sub check_collaborators {
       my ($symb,$uname,$udom,$record,$handgrade,$counter) = @_;
       my ($result,@col_fullnames);
       my ($classlist,undef,$fullname) = &getclasslist('all','0');
       foreach my $part (keys(%$handgrade)) {
    my $ncol = &Apache::lonnet::EXT('resource.'.$part.
    '.maxcollaborators',
    $symb,$udom,$uname);
    next if ($ncol <= 0);
    $part =~ s/\_/\./g;
    next if ($record->{'resource.'.$part.'.collaborators'} eq '');
    my (@good_collaborators, @bad_collaborators);
    foreach my $possible_collaborator
       (split(/,?\s+/,$record->{'resource.'.$part.'.collaborators'})) { 
       $possible_collaborator =~ s/[\$\^\(\)]//g;
       next if ($possible_collaborator eq '');
       my ($co_name,$co_dom) = split(/\@|:/,$possible_collaborator);
       $co_dom = $udom if (! defined($co_dom) || $co_dom =~ /^domain$/i);
       next if ($co_name eq $uname && $co_dom eq $udom);
       # Doing this grep allows 'fuzzy' specification
       my @matches = grep(/^\Q$co_name\E:\Q$co_dom\E$/i, 
          keys(%$classlist));
       if (! scalar(@matches)) {
    push(@bad_collaborators, $possible_collaborator);
       } else {
    push(@good_collaborators, @matches);
       }
    }
    if (scalar(@good_collaborators) != 0) {
       $result.='<br />'.&mt('Collaborators: ');
       foreach my $name (@good_collaborators) {
    my ($lastname,$givenn) = split(/,/,$$fullname{$name});
    push(@col_fullnames, $givenn.' '.$lastname);
    $result.=$fullname->{$name}.'&nbsp; &nbsp; &nbsp;';
       }
       $result.='<br />'."\n";
       my ($part)=split(/\./,$part);
       $result.='<input type="hidden" name="collaborator'.$counter.
    '" value="'.$part.':'.(join ':',@good_collaborators).'" />'.
    "\n";
    }
    if (scalar(@bad_collaborators) > 0) {
       $result.='<div class="LC_warning">';
       $result.=&mt('This student has submitted [quant,_1,invalid collaborator]: [_2]',scalar(@bad_collaborators),join(', ',@bad_collaborators));
       $result .= '</div>';
    }         
    if (scalar(@bad_collaborators > $ncol)) {
       $result .= '<div class="LC_warning">';
       $result .= &mt('This student has submitted too many '.
    'collaborators.  Maximum is [_1].',$ncol);
       $result .= '</div>';
    }
       }
       return ($result,$fullname,\@col_fullnames);
   }
   
 #--- Retrieve the last submission for all the parts  #--- Retrieve the last submission for all the parts
 sub get_last_submission {  sub get_last_submission {
     my ($returnhash)=@_;      my ($returnhash)=@_;
Line 2786  sub version_selected_portfile { Line 2934  sub version_selected_portfile {
     my $new_answer;      my $new_answer;
     $env{'form.copy'} = &Apache::lonnet::getfile("/uploaded/$domain/$stu_name/portfolio$directory$file_name");      $env{'form.copy'} = &Apache::lonnet::getfile("/uploaded/$domain/$stu_name/portfolio$directory$file_name");
     if($env{'form.copy'} eq '-1') {      if($env{'form.copy'} eq '-1') {
         &Apache::lonnet::logthis('problem getting file '.$file_name);  
         $new_answer = 'problem getting file';          $new_answer = 'problem getting file';
     } else {      } else {
         $new_answer = $answer_name.'.'.$version.'.'.$answer_ext;          $new_answer = $answer_name.'.'.$version.'.'.$answer_ext;
Line 3007  sub viewgrades { Line 3154  sub viewgrades {
     $result.=&jscriptNform($symb);      $result.=&jscriptNform($symb);
   
     #beginning of class grading form      #beginning of class grading form
       my $stu_status = join(':',&Apache::loncommon::get_env_multiple('form.Status'));
     $result.= '<form action="/adm/grades" method="post" name="classgrade">'."\n".      $result.= '<form action="/adm/grades" method="post" name="classgrade">'."\n".
  '<input type="hidden" name="symb"    value="'.&Apache::lonenc::check_encrypt($symb).'" />'."\n".   '<input type="hidden" name="symb"    value="'.&Apache::lonenc::check_encrypt($symb).'" />'."\n".
  '<input type="hidden" name="command" value="editgrades" />'."\n".   '<input type="hidden" name="command" value="editgrades" />'."\n".
  &build_section_inputs().   &build_section_inputs().
  '<input type="hidden" name="saveState" value="'.$env{'form.saveState'}.'" />'."\n".   '<input type="hidden" name="saveState" value="'.$env{'form.saveState'}.'" />'."\n".
  '<input type="hidden" name="Status" value="'.$env{'form.Status'}.'" />'."\n".   '<input type="hidden" name="Status" value="'.$env{'stu_status'}.'" />'."\n".
  '<input type="hidden" name="probTitle" value="'.$env{'form.probTitle'}.'" />'."\n";   '<input type="hidden" name="probTitle" value="'.$env{'form.probTitle'}.'" />'."\n";
   
     my $sectionClass;      my $sectionClass;
Line 3025  sub viewgrades { Line 3173  sub viewgrades {
  $sectionClass=&mt('Students in Section(s) [_1]',$section_display).'</h3>';   $sectionClass=&mt('Students in Section(s) [_1]',$section_display).'</h3>';
     }      }
     $result.='<h3>'.&mt('Assign Common Grade To [_1]',$sectionClass);      $result.='<h3>'.&mt('Assign Common Grade To [_1]',$sectionClass);
     $result.= '<table border=0><tr><td bgcolor="#777777">'."\n".      $result.= &Apache::loncommon::start_data_table();
  '<table border=0><tr bgcolor="#ffffdd"><td>';  
     #radio buttons/text box for assigning points for a section or class.      #radio buttons/text box for assigning points for a section or class.
     #handles different parts of a problem      #handles different parts of a problem
     my ($partlist,$handgrade,$responseType) = &response_type($symb);      my ($partlist,$handgrade,$responseType) = &response_type($symb);
     my %weight = ();      my %weight = ();
     my $ctsparts = 0;      my $ctsparts = 0;
     $result.='<table border="0">';  
     my %seen = ();      my %seen = ();
     my @part_response_id = &flatten_responseType($responseType);      my @part_response_id = &flatten_responseType($responseType);
     foreach my $part_response_id (@part_response_id) {      foreach my $part_response_id (@part_response_id) {
Line 3044  sub viewgrades { Line 3190  sub viewgrades {
  my $wgt = &Apache::lonnet::EXT('resource.'.$partid.'.weight',$symb);   my $wgt = &Apache::lonnet::EXT('resource.'.$partid.'.weight',$symb);
  $weight{$partid} = $wgt eq '' ? '1' : $wgt;   $weight{$partid} = $wgt eq '' ? '1' : $wgt;
   
    $result.=&Apache::loncommon::start_data_table_row().'<td>';
  $result.='<input type="hidden" name="partid_'.   $result.='<input type="hidden" name="partid_'.
     $ctsparts.'" value="'.$partid.'" />'."\n";      $ctsparts.'" value="'.$partid.'" />'."\n";
  $result.='<input type="hidden" name="weight_'.   $result.='<input type="hidden" name="weight_'.
     $partid.'" value="'.$weight{$partid}.'" />'."\n";      $partid.'" value="'.$weight{$partid}.'" />'."\n";
  my $display_part=&get_display_part($partid,$symb);   my $display_part=&get_display_part($partid,$symb);
  $result.='<tr><td><b>Part:</b> '.$display_part.'&nbsp; &nbsp;<b>Point:</b> </td><td>';   $result.=
       '<b>Part:</b> '.$display_part.'&nbsp; &nbsp;<b>Point:</b> </td><td>';
  $result.='<table border="0"><tr>';     $result.='<table border="0"><tr>';  
  my $ctr = 0;   my $ctr = 0;
  while ($ctr<=$weight{$partid}) { # display radio buttons in a nice table 10 across   while ($ctr<=$weight{$partid}) { # display radio buttons in a nice table 10 across
Line 3064  sub viewgrades { Line 3212  sub viewgrades {
     $partid.'" size="4" '.'onChange="javascript:writePoint(\''.      $partid.'" size="4" '.'onChange="javascript:writePoint(\''.
  $partid.'\','.$weight{$partid}.',\'textval\')" /> /'.   $partid.'\','.$weight{$partid}.',\'textval\')" /> /'.
     $weight{$partid}.' (problem weight)</td>'."\n";      $weight{$partid}.' (problem weight)</td>'."\n";
  $result.= '</td><td><select name="SELVAL_'.$partid.'"'.   $result.= '<td><select name="SELVAL_'.$partid.'"'.
     'onChange="javascript:writeRadText(\''.$partid.'\','.      'onChange="javascript:writeRadText(\''.$partid.'\','.
  $weight{$partid}.')"> '.   $weight{$partid}.')"> '.
     '<option selected="selected"> </option>'.      '<option selected="selected"> </option>'.
     '<option>excused</option>'.      '<option>excused</option>'.
     '<option>reset status</option></select></td>'.      '<option>reset status</option></select></td>'.
             '<td><label><input type="checkbox" name="FORCE_'.$partid.'" /> Override "Correct"</label></td></tr>'."\n";              '<td><label><input type="checkbox" name="FORCE_'.$partid.'" /> Override "Correct"</label></td>'.&Apache::loncommon::end_data_table_row()."\n";
  $ctsparts++;   $ctsparts++;
     }      }
     $result.='</table>'.'</td></tr></table>'.'</td></tr></table>'."\n".      $result.=&Apache::loncommon::end_data_table()."\n".
  '<input type="hidden" name="totalparts" value="'.$ctsparts.'" />';   '<input type="hidden" name="totalparts" value="'.$ctsparts.'" />';
     $result.='<input type="button" value="Revert to Default" '.      $result.='<input type="button" value="Revert to Default" '.
  'onClick="javascript:resetEntry('.$ctsparts.');" target="_self" />';   'onClick="javascript:resetEntry('.$ctsparts.');" />';
   
     #table listing all the students in a section/class      #table listing all the students in a section/class
     #header of table      #header of table
     $result.= '<h3>Assign Grade to Specific Students in '.$sectionClass;      $result.= '<h3>Assign Grade to Specific Students in '.$sectionClass;
     $result.= '<table border=0><tr><td bgcolor="#777777">'."\n".      $result.= &Apache::loncommon::start_data_table().
  '<table border=0><tr bgcolor="#deffff"><td>&nbsp;<b>No.</b>&nbsp;</td>'.   &Apache::loncommon::start_data_table_header_row().
  '<td>'.&nameUserString('header')."</td>\n";   '<th>No.</th>'.
    '<th>'.&nameUserString('header')."</th>\n";
     my (@parts) = sort(&getpartlist($symb));      my (@parts) = sort(&getpartlist($symb));
     my (undef,undef,$url)=&Apache::lonnet::decode_symb($symb);      my (undef,undef,$url)=&Apache::lonnet::decode_symb($symb);
     my @partids = ();      my @partids = ();
Line 3095  sub viewgrades { Line 3244  sub viewgrades {
         push(@partids, $partid);          push(@partids, $partid);
  my $display_part=&get_display_part($partid,$symb);   my $display_part=&get_display_part($partid,$symb);
  if ($display =~ /^Partial Credit Factor/) {   if ($display =~ /^Partial Credit Factor/) {
     $result.='<td><b>Score Part:</b> '.$display_part.      $result.='<th>Score Part: '.$display_part.
  ' <br /><b>(weight = '.$weight{$partid}.')</b></td>'."\n";   ' <br />(weight = '.$weight{$partid}.')</th>'."\n";
     next;      next;
  } else {   } else {
     $display =~s/\[Part: \Q$partid\E\]/Part:<\/b> $display_part/;      $display =~s/\[Part: \Q$partid\E\]/Part:<\/b> $display_part/;
  }   }
  $display =~ s|Problem Status|Grade Status<br />|;   $display =~ s|Problem Status|Grade Status<br />|;
  $result.='<td><b>'.$display.'</td>'."\n";   $result.='<th>'.$display.'</th>'."\n";
     }      }
     $result.='</tr>';      $result.=&Apache::loncommon::end_data_table_header_row();
   
     my %last_resets =       my %last_resets = 
  &get_last_resets($symb,$env{'request.course.id'},\@partids);   &get_last_resets($symb,$env{'request.course.id'},\@partids);
Line 3124  sub viewgrades { Line 3273  sub viewgrades {
  $result.=&viewstudentgrade($symb,$env{'request.course.id'},   $result.=&viewstudentgrade($symb,$env{'request.course.id'},
    $_,$$fullname{$_},\@parts,\%weight,$ctr,\%last_resets);     $_,$$fullname{$_},\@parts,\%weight,$ctr,\%last_resets);
     }      }
     $result.='</table></td></tr></table>';      $result.=&Apache::loncommon::end_data_table();
     $result.='<input type="hidden" name="total" value="'.$ctr.'" />'."\n";      $result.='<input type="hidden" name="total" value="'.$ctr.'" />'."\n";
     $result.='<input type="button" value="Save" '.      $result.='<input type="button" value="Save" '.
  'onClick="javascript:submit();" target="_self" /></form>'."\n";   'onClick="javascript:submit();" target="_self" /></form>'."\n";
     if (scalar(%$fullname) eq 0) {      if (scalar(%$fullname) eq 0) {
  my $colspan=3+scalar(@parts);   my $colspan=3+scalar(@parts);
  my $section_display = join (", ",&Apache::loncommon::get_env_multiple('form.section'));   my $section_display = join (", ",&Apache::loncommon::get_env_multiple('form.section'));
           my $stu_status = join(' or ',&Apache::loncommon::get_env_multiple('form.Status'));
  $result='<span class="LC_warning">'.   $result='<span class="LC_warning">'.
     &mt('There are no students in section(s) [_1] with enrollment status [_2] to modify or grade',      &mt('There are no students in section(s) [_1] with enrollment status [_2] to modify or grade',
         $section_display, $env{'form.Status'}).          $section_display, $stu_status).
     '</span>';      '</span>';
     }      }
     $result.=&show_grading_menu_form($symb);      $result.=&show_grading_menu_form($symb);
Line 3146  sub viewstudentgrade { Line 3296  sub viewstudentgrade {
     my ($uname,$udom) = split(/:/,$student);      my ($uname,$udom) = split(/:/,$student);
     my %record=&Apache::lonnet::restore($symb,$courseid,$udom,$uname);      my %record=&Apache::lonnet::restore($symb,$courseid,$udom,$uname);
     my %aggregates = ();       my %aggregates = (); 
     my $result='<tr bgcolor="#ffffdd"><td align="right">'.      my $result=&Apache::loncommon::start_data_table_row().'<td align="right">'.
  '<input type="hidden" name="ctr'.($ctr-1).'" value="'.$student.'" />'.   '<input type="hidden" name="ctr'.($ctr-1).'" value="'.$student.'" />'.
  "\n".$ctr.'&nbsp;</td><td>&nbsp;'.   "\n".$ctr.'&nbsp;</td><td>&nbsp;'.
  '<a href="javascript:viewOneStudent(\''.$uname.'\',\''.$udom.   '<a href="javascript:viewOneStudent(\''.$uname.'\',\''.$udom.
Line 3201  sub viewstudentgrade { Line 3351  sub viewstudentgrade {
  'value="'.$score.'" size="4" /></td>'."\n";   'value="'.$score.'" size="4" /></td>'."\n";
  }   }
     }      }
     $result.='</tr>';      $result.=&Apache::loncommon::end_data_table_row();
     return $result;      return $result;
 }  }
   
Line 3212  sub editgrades { Line 3362  sub editgrades {
   
     my $symb=&get_symb($request);      my $symb=&get_symb($request);
     my $section_display = join (", ",&Apache::loncommon::get_env_multiple('form.section'));      my $section_display = join (", ",&Apache::loncommon::get_env_multiple('form.section'));
     my $title='<h3><span class="LC_info">'.&mt('Current Grade Status').'</span></h3>';      my $title='<h2>'.&mt('Current Grade Status').'</h2>';
     $title.='<h4>'.&mt('<b>Current Resource: </b>[_1]',$env{'form.probTitle'}).'</h4><br />'."\n";      $title.='<h4>'.&mt('<b>Current Resource: </b>[_1]',$env{'form.probTitle'}).'</h4>'."\n";
     $title.='<h4>'.&mt('<b>Section: </b>[_1]',$section_display).'</h4>'."\n";      $title.='<h4>'.&mt('<b>Section: </b>[_1]',$section_display).'</h4>'."\n";
   
     my $result= '<table border="0"><tr><td bgcolor="#777777">'."\n";      my $result= &Apache::loncommon::start_data_table().
     $result.= '<table border="0"><tr bgcolor="#deffff">'.   &Apache::loncommon::start_data_table_header_row().
  '<td rowspan=2 valign="center">&nbsp;<b>No.</b>&nbsp;</td>'.   '<th rowspan="2" valign="middle">'.&mt('No.').'</th>'.
  '<td rowspan=2 valign="center">'.&nameUserString('header')."</td>\n";   '<th rowspan="2" valign="middle">'.&nameUserString('header')."</th>\n";
   
     my %scoreptr = (      my %scoreptr = (
     'correct'  =>'correct_by_override',      'correct'  =>'correct_by_override',
     'incorrect'=>'incorrect_by_override',      'incorrect'=>'incorrect_by_override',
Line 3245  sub editgrades { Line 3394  sub editgrades {
     }      }
     my (undef,undef,$url) = &Apache::lonnet::decode_symb($symb);      my (undef,undef,$url) = &Apache::lonnet::decode_symb($symb);
     foreach my $partid (@partid) {      foreach my $partid (@partid) {
  $header .= '<td align="center">&nbsp;<b>Old Score</b>&nbsp;</td>'.   $header .= '<th align="center">Old Score</th>'.
     '<td align="center">&nbsp;<b>New Score</b>&nbsp;</td>';      '<th align="center">New Score</th>';
  $columns{$partid}=2;   $columns{$partid}=2;
  foreach my $stores (@parts) {   foreach my $stores (@parts) {
     my ($part,$type) = &split_part_type($stores);      my ($part,$type) = &split_part_type($stores);
Line 3255  sub editgrades { Line 3404  sub editgrades {
     my $display=&Apache::lonnet::metadata($url,$stores.'.display');      my $display=&Apache::lonnet::metadata($url,$stores.'.display');
     $display =~ s/\[Part: (\w)+\]//;      $display =~ s/\[Part: (\w)+\]//;
     $display =~ s/Number of Attempts/Tries/;      $display =~ s/Number of Attempts/Tries/;
     $header .= '<td align="center">&nbsp;<b>Old '.$display.'</b>&nbsp;</td>'.      $header .= '<th align="center">Old '.$display.'</th>'.
  '<td align="center">&nbsp;<b>New '.$display.'</b>&nbsp;</td>';   '<th align="center">New '.$display.'</th>';
     $columns{$partid}+=2;      $columns{$partid}+=2;
  }   }
     }      }
     foreach my $partid (@partid) {      foreach my $partid (@partid) {
  my $display_part=&get_display_part($partid,$symb);   my $display_part=&get_display_part($partid,$symb);
  $result .= '<td colspan="'.$columns{$partid}.   $result .= '<th colspan="'.$columns{$partid}.
     '" align="center"><b>Part:</b> '.$display_part.      '" align="center">Part: '.$display_part.
     ' (Weight = '.$weight{$partid}.')</td>';      ' (Weight = '.$weight{$partid}.')</th>';
   
     }      }
     $result .= '</tr><tr bgcolor="#deffff">';      $result .= &Apache::loncommon::end_data_table_header_row().
     $result .= $header;   &Apache::loncommon::start_data_table_header_row().
     $result .= '</tr>'."\n";   $header.
     my $noupdate;   &Apache::loncommon::end_data_table_header_row();
       my @noupdate;
     my ($updateCtr,$noupdateCtr) = (1,1);      my ($updateCtr,$noupdateCtr) = (1,1);
     for ($i=0; $i<$env{'form.total'}; $i++) {      for ($i=0; $i<$env{'form.total'}; $i++) {
  my $line;   my $line;
Line 3282  sub editgrades { Line 3432  sub editgrades {
  my $usec=$classlist->{"$uname:$udom"}[5];   my $usec=$classlist->{"$uname:$udom"}[5];
  if (!&canmodify($usec)) {   if (!&canmodify($usec)) {
     my $numcols=scalar(@partid)*4+2;      my $numcols=scalar(@partid)*4+2;
     $noupdate.=$line."<td colspan=\"$numcols\"><span class=\"LC_warning\">Not allowed to modify student</span></td></tr>";      push(@noupdate,
    $line."<td colspan=\"$numcols\"><span class=\"LC_warning\">Not allowed to modify student</span></td></tr>");
     next;      next;
  }   }
         my %aggregate = ();          my %aggregate = ();
Line 3351  sub editgrades { Line 3502  sub editgrades {
     '<td align="center">'.$awarded.'&nbsp;</td>';      '<td align="center">'.$awarded.'&nbsp;</td>';
     }      }
  }   }
  $line.='</tr>'."\n";   $line.="\n";
   
  my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};   my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
  my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};   my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
Line 3384  sub editgrades { Line 3535  sub editgrades {
  }   }
     }      }
   
     $result.='<tr bgcolor="#ffffde"><td align="right">&nbsp;'.$updateCtr.'&nbsp;</td>'.$line;      $result.=&Apache::loncommon::start_data_table_row().
    '<td align="right">&nbsp;'.$updateCtr.'&nbsp;</td>'.$line.
    &Apache::loncommon::end_data_table_row();
     $updateCtr++;      $updateCtr++;
  } else {   } else {
     $noupdate.='<tr bgcolor="#ffffde"><td align="right">&nbsp;'.$noupdateCtr.'&nbsp;</td>'.$line;      push(@noupdate,
    '<td align="right">&nbsp;'.$noupdateCtr.'&nbsp;</td>'.$line);
     $noupdateCtr++;      $noupdateCtr++;
  }   }
         if ($aggregateflag) {          if ($aggregateflag) {
Line 3395  sub editgrades { Line 3549  sub editgrades {
   $cdom,$cnum);    $cdom,$cnum);
         }          }
     }      }
     if ($noupdate) {      if (@noupdate) {
 # my $numcols=(scalar(@partid)*(scalar(@parts)-1)*2)+3;  # my $numcols=(scalar(@partid)*(scalar(@parts)-1)*2)+3;
  my $numcols=scalar(@partid)*4+2;   my $numcols=scalar(@partid)*4+2;
  $result .= '<tr bgcolor="#ffffff"><td align="center" colspan="'.$numcols.'">No Changes Occurred For the Students Below</td></tr><tr bgcolor="#ffffde">'.$noupdate;   $result .= &Apache::loncommon::start_data_table_row('LC_empty_row').
       '<td align="center" colspan="'.$numcols.'">No Changes Occurred For the Students Below</td>'.
       &Apache::loncommon::end_data_table_row();
    foreach my $line (@noupdate) {
       $result.=
    &Apache::loncommon::start_data_table_row().
    $line.
    &Apache::loncommon::end_data_table_row();
    }
     }      }
     $result .= '</table></td></tr></table>'."\n".      $result .= &Apache::loncommon::end_data_table().
  &show_grading_menu_form ($symb);   &show_grading_menu_form($symb);
     my $msg = '<br /><b>Number of records updated = '.$rec_update.      my $msg = '<p><b>Number of records updated = '.$rec_update.
  ' for '.$count.' student'.($count <= 1 ? '' : 's').'.</b><br />'.   ' for '.$count.' student'.($count <= 1 ? '' : 's').'.</b><br />'.
  '<b>Total number of students = '.$env{'form.total'}.'</b><br />';   '<b>Total number of students = '.$env{'form.total'}.'</b></p>';
     return $title.$msg.$result;      return $title.$msg.$result;
 }  }
   
Line 3796  sub csvuploadassign { Line 3958  sub csvuploadassign {
                 if ($wgt) {                  if ($wgt) {
                     $entries{$fields{$dest}}=~s/\s//g;                      $entries{$fields{$dest}}=~s/\s//g;
                     my $pcr=$entries{$fields{$dest}} / $wgt;                      my $pcr=$entries{$fields{$dest}} / $wgt;
                     my $award='correct_by_override';                      my $award=($pcr == 0) ? 'incorrect_by_override'
                                             : 'correct_by_override';
                     $grades{"resource.$part.awarded"}=$pcr;                      $grades{"resource.$part.awarded"}=$pcr;
                     $grades{"resource.$part.solved"}=$award;                      $grades{"resource.$part.solved"}=$award;
                     $points{$part}=1;                      $points{$part}=1;
Line 3818  sub csvuploadassign { Line 3981  sub csvuploadassign {
  }   }
  if (! %grades) { push(@skipped,"$username:$domain no data to save"); }   if (! %grades) { push(@skipped,"$username:$domain no data to save"); }
  $grades{"resource.regrader"}="$env{'user.name'}:$env{'user.domain'}";   $grades{"resource.regrader"}="$env{'user.name'}:$env{'user.domain'}";
 # &Apache::lonnet::logthis(" storing ".(join('-',%grades)));  
  my $result=&Apache::lonnet::cstore(\%grades,$symb,   my $result=&Apache::lonnet::cstore(\%grades,$symb,
    $env{'request.course.id'},     $env{'request.course.id'},
    $domain,$username);     $domain,$username);
Line 3917  LISTJAVASCRIPT Line 4079  LISTJAVASCRIPT
  '<label><input type="radio" name="lastSub" value="all" /> all details</label>'."\n";   '<label><input type="radio" name="lastSub" value="all" /> all details</label>'."\n";
           
     $result.=&build_section_inputs();      $result.=&build_section_inputs();
     $result.='<input type="hidden" name="Status"  value="'.$env{'form.Status'}.'" />'."\n".      my $stu_status = join(':',&Apache::loncommon::get_env_multiple('form.Status'));
       $result.='<input type="hidden" name="Status"  value="'.$stu_status.'" />'."\n".
  '<input type="hidden" name="command" value="displayPage" />'."\n".   '<input type="hidden" name="command" value="displayPage" />'."\n".
  '<input type="hidden" name="symb"    value="'.&Apache::lonenc::check_encrypt($symb).'" />'."\n".   '<input type="hidden" name="symb"    value="'.&Apache::lonenc::check_encrypt($symb).'" />'."\n".
  '<input type="hidden" name="saveState" value="'.$env{'form.saveState'}.'" />'."<br />\n";   '<input type="hidden" name="saveState" value="'.$env{'form.saveState'}.'" />'."<br />\n";
Line 4147  sub displaySubByDates { Line 4310  sub displaySubByDates {
     my $isCODE=0;      my $isCODE=0;
     my $isTask = ($symb =~/\.task$/);      my $isTask = ($symb =~/\.task$/);
     if (exists($record->{'resource.CODE'})) { $isCODE=1; }      if (exists($record->{'resource.CODE'})) { $isCODE=1; }
     my $studentTable='<table border="0" width="100%"><tr><td bgcolor="#777777">'.      my $studentTable=&Apache::loncommon::start_data_table().
  '<table border="0" width="100%"><tr bgcolor="#e6ffff">'.   &Apache::loncommon::start_data_table_header_row().
  '<td><b>Date/Time</b></td>'.   '<th>'.&mt('Date/Time').'</th>'.
  ($isCODE?'<td><b>CODE</b></td>':'').   ($isCODE?'<th>'.&mt('CODE').'</th>':'').
  '<td><b>Submission</b></td>'.   '<th>'.&mt('Submission').'</th>'.
  '<td><b>Status&nbsp;</b></td></tr>';   '<th>'.&mt('Status').'</th>'.
    &Apache::loncommon::end_data_table_header_row();
     my ($version);      my ($version);
     my %mark;      my %mark;
     my %orders;      my %orders;
     $mark{'correct_by_student'} = $checkIcon;      $mark{'correct_by_student'} = $checkIcon;
     if (!exists($$record{'1:timestamp'})) {      if (!exists($$record{'1:timestamp'})) {
  return '<br />&nbsp;<span class="LC_warning">Nothing submitted - no attempts</span><br />';   return '<br />&nbsp;<span class="LC_warning">'.&mt('Nothing submitted - no attempts').'</span><br />';
     }      }
   
     my $interaction;      my $interaction;
     for ($version=1;$version<=$$record{'version'};$version++) {      for ($version=1;$version<=$$record{'version'};$version++) {
  my $timestamp = scalar(localtime($$record{$version.':timestamp'}));   my $timestamp = 
       &Apache::lonlocal::locallocaltime($$record{$version.':timestamp'});
  if (exists($$record{$version.':resource.0.version'})) {   if (exists($$record{$version.':resource.0.version'})) {
     $interaction = $$record{$version.':resource.0.version'};      $interaction = $$record{$version.':resource.0.version'};
  }   }
   
  my $where = ($isTask ? "$version:resource.$interaction"   my $where = ($isTask ? "$version:resource.$interaction"
              : "$version:resource");               : "$version:resource");
  #&Apache::lonnet::logthis(" got $where");   $studentTable.=&Apache::loncommon::start_data_table_row().
  $studentTable.='<tr bgcolor="#ffffff" valign="top"><td>'.$timestamp.'</td>';      '<td>'.$timestamp.'</td>';
  if ($isCODE) {   if ($isCODE) {
     $studentTable.='<td>'.$record->{$version.':resource.CODE'}.'</td>';      $studentTable.='<td>'.$record->{$version.':resource.CODE'}.'</td>';
  }   }
Line 4190  sub displaySubByDates { Line 4355  sub displaySubByDates {
   
     my ($responseId)= ($isTask ? ($matchKey=~ /^resource\.(.*?)\.\Q$partid\E\.award$/)      my ($responseId)= ($isTask ? ($matchKey=~ /^resource\.(.*?)\.\Q$partid\E\.award$/)
                : ($matchKey=~ /^resource\.\Q$partid\E\.(.*?)\.submission$/));                 : ($matchKey=~ /^resource\.\Q$partid\E\.(.*?)\.submission$/));
     #&Apache::lonnet::logthis("match $matchKey $responseId (".$$record{$version.':'.$matchKey});      $displaySub[0].='<b>'.&mt('Part:').'</b>&nbsp;'.$display_part.'&nbsp;';
     $displaySub[0].='<b>Part:</b>&nbsp;'.$display_part.'&nbsp;';      $displaySub[0].='<span class="LC_internal_info">('.&mt('ID').'&nbsp;'.
     $displaySub[0].='<span class="LC_internal_info">(ID&nbsp;'.  
  $responseId.')</span>&nbsp;<b>';   $responseId.')</span>&nbsp;<b>';
     if ($$record{"$where.$partid.tries"} eq '') {      if ($$record{"$where.$partid.tries"} eq '') {
  $displaySub[0].='Trial&nbsp;not&nbsp;counted';   $displaySub[0].=&mt('Trial&nbsp;not&nbsp;counted');
     } else {      } else {
  $displaySub[0].='Trial&nbsp;'.   $displaySub[0].=&mt('Trial&nbsp;[_1]',
     $$record{"$where.$partid.tries"};      $$record{"$where.$partid.tries"});
     }      }
     my $responseType=($isTask ? 'Task'      my $responseType=($isTask ? 'Task'
                                               : $responseType->{$partid}->{$responseId});                                                : $responseType->{$partid}->{$responseId});
Line 4238  sub displaySubByDates { Line 4402  sub displaySubByDates {
  }   }
  $studentTable.='<td>'.$displaySub[0].'&nbsp;</td><td>'.$displaySub[1];   $studentTable.='<td>'.$displaySub[0].'&nbsp;</td><td>'.$displaySub[1];
  if ($displaySub[2]) {   if ($displaySub[2]) {
     $studentTable.='Manually graded by '.$displaySub[2];      $studentTable.=&mt('Manually graded by [_1]',$displaySub[2]);
  }   }
  $studentTable.='&nbsp;</td></tr>';   $studentTable.='&nbsp;</td>'.
           &Apache::loncommon::end_data_table_row();
     }      }
     $studentTable.='</table></td></tr></table>';      $studentTable.=&Apache::loncommon::end_data_table();
     return $studentTable;      return $studentTable;
 }  }
   
Line 4459  the homework problem. Line 4623  the homework problem.
   
 =over 4  =over 4
   
 =cut  
   
   
 =pod   
   
 =item defaultFormData  =item defaultFormData
   
   Returns html hidden inputs used to hold context/default values.    Returns html hidden inputs used to hold context/default values.
Line 4475  the homework problem. Line 4636  the homework problem.
   
 sub defaultFormData {  sub defaultFormData {
     my ($symb)=@_;      my ($symb)=@_;
     return '      return '<input type="hidden" name="symb"    value="'.&Apache::lonenc::check_encrypt($symb).'" />'."\n".
       <input type="hidden" name="symb"    value="'.&Apache::lonenc::check_encrypt($symb).'" />'."\n".  
      '<input type="hidden" name="saveState" value="'.$env{'form.saveState'}.'" />'."\n".       '<input type="hidden" name="saveState" value="'.$env{'form.saveState'}.'" />'."\n".
      '<input type="hidden" name="probTitle" value="'.$env{'form.probTitle'}.'" />'."\n";       '<input type="hidden" name="probTitle" value="'.$env{'form.probTitle'}.'" />'."\n";
 }  }
   
   
 =pod   =pod 
   
 =item getSequenceDropDown  =item getSequenceDropDown
Line 4782  SCANTRONFORM Line 4943  SCANTRONFORM
     </tr>      </tr>
 SCANTRONFORM  SCANTRONFORM
   
     $r->print(<<SCANTRONFORM);      $r->print('<tr><td bgcolor="#777777">');
   </table>      &Apache::lonpickcode::code_list($r,2);
 $grading_menu_button      $r->print('</td></tr></table>');
 SCANTRONFORM      $r->print($grading_menu_button);
   
     return      return
 }  }
   
Line 5070  sub scan_data { Line 5230  sub scan_data {
   
      if just_header was not true these key may also exist       if just_header was not true these key may also exist
   
        missingerror - a list of bubbled line numbers that had a blank bubble         missingerror - a list of bubble ranges that are considered to be answers
                       that is considered an error (if the operator had already                        to a single question that don't have any bubbles filled in.
                       okayed a blank bubble line as really being blank then                        Of the form questionnumber:firstbubblenumber:count.
                       that bubble line number won't appear here.         doubleerror  - a list of bubble ranges that are considered to be answers
        doubleerror  - a list of bubbled line numbers that had more than one                        to a single question that have more than one bubble filled in.
                       bubble filled in and has not been corrected by the                        Of the form questionnumber::firstbubblenumber:count
                       operator     
                   In the above, count is the number of bubble responses in the
                   input line needed to represent the possible answers to the question.
                   e.g. a radioresponse with 15 choices in an answer sheet with 10 choices
                   per line would have count = 2.
   
        maxquest     - the number of the last bubble line that was parsed         maxquest     - the number of the last bubble line that was parsed
   
        (<number> starts at 1)         (<number> starts at 1)
Line 5091  sub scan_data { Line 5256  sub scan_data {
   
 sub scantron_parse_scanline {  sub scantron_parse_scanline {
     my ($line,$whichline,$scantron_config,$scan_data,$just_header)=@_;      my ($line,$whichline,$scantron_config,$scan_data,$just_header)=@_;
   
     my %record;      my %record;
     my $questions=substr($line,$$scantron_config{'Qstart'}-1);  # Answers      my $questions=substr($line,$$scantron_config{'Qstart'}-1);  # Answers
     my $data=substr($line,0,$$scantron_config{'Qstart'}-1);     # earlier stuff      my $data=substr($line,0,$$scantron_config{'Qstart'}-1);     # earlier stuff
Line 5127  sub scantron_parse_scanline { Line 5293  sub scantron_parse_scanline {
   
     my @alphabet=('A'..'Z');      my @alphabet=('A'..'Z');
     my $questnum=0;      my $questnum=0;
     while ($questions) {      my $ansnum  =1; # Multiple 'answer lines'/question.
   
       chomp($questions); # Get rid of any trailing \n.
       $questions =~ s/\r$//;      # Get rid of trailing \r too (MAC or Win uploads).
       while (length($questions)) {
    my $answers_needed = $bubble_lines_per_response{$questnum};
    my $answer_length  = $$scantron_config{'Qlength'} * $answers_needed;
   
   
   
  $questnum++;   $questnum++;
  my $currentquest=substr($questions,0,$$scantron_config{'Qlength'});   my $currentquest = substr($questions,0,$answer_length);
  substr($questions,0,$$scantron_config{'Qlength'})='';   $questions       = substr($questions,0,$answer_length)='';
  if (length($currentquest) < $$scantron_config{'Qlength'}) { next; }   if (length($currentquest) < $answer_length) { next; }
   
    # Qon letter implies for each slot in currentquest we have:
    #    ? or * for doubles a letter in A-Z for a bubble and
           #    about anything else (esp. a value of Qoff for missing
    #    bubbles.
   
   
  if ($$scantron_config{'Qon'} eq 'letter') {   if ($$scantron_config{'Qon'} eq 'letter') {
     if ($currentquest eq '?'  
  || $currentquest eq '*') {      if ($currentquest =~ /\?/
    || $currentquest =~ /\*/
    || (&occurence_count($currentquest, "[A-Z]") > 1)) {
  push(@{$record{'scantron.doubleerror'}},$questnum);   push(@{$record{'scantron.doubleerror'}},$questnum);
  $record{"scantron.$questnum.answer"}='';   for (my $ans = 0; $ans < $answers_needed; $ans++) { 
       my $bubble = substr($currentquest, $ans, 1);
       if ($bubble =~ /[A-Z]/ ) {
    $record{"scantron.$ansnum.answer"} = $bubble;
       } else {
    $record{"scantron.$ansnum.answer"}='';
       }
       $ansnum++;
    }
   
     } elsif (!defined($currentquest)      } elsif (!defined($currentquest)
      || $currentquest eq $$scantron_config{'Qoff'}       || (&occurence_count($currentquest, $$scantron_config{'Qoff'}) == length($currentquest))
      || $currentquest !~ /^[A-Z]$/) {       || (&occurence_count($currentquest, "[A-Z]") == 0)) {
  $record{"scantron.$questnum.answer"}='';   for (my $ans = 0; $ans < $answers_needed; $ans++ ) {
       $record{"scantron.$ansnum.answer"}='';
       $ansnum++;
   
    }
  if (!&scan_data($scan_data,"$whichline.no_bubble.$questnum")) {   if (!&scan_data($scan_data,"$whichline.no_bubble.$questnum")) {
     push(@{$record{"scantron.missingerror"}},$questnum);      push(@{$record{"scantron.missingerror"}},$questnum);
      #  $ansnum += $answers_needed;
  }   }
     } else {      } else {
  $record{"scantron.$questnum.answer"}=$currentquest;   for (my $ans = 0; $ans < $answers_needed; $ans++) {
       $record{"scantron.$ansnum.answer"} = substr($currentquest, $ans, 1);
       $ansnum++;
    }
     }      }
   
    # Qon 'number' implies each slot gives a digit that indexes the
    #    the bubbles filled or Qoff or a non number for unbubbled lines.
           #    and *? for double bubbles on a line.
    #    these answers are also stored as letters.
   
  } elsif ($$scantron_config{'Qon'} eq 'number') {   } elsif ($$scantron_config{'Qon'} eq 'number') {
     if ($currentquest eq '?'      if ($currentquest =~ /\?/
  || $currentquest eq '*') {   || $currentquest =~ /\*/
    || (&occurence_count($currentquest, '\d') > 1)) {
  push(@{$record{'scantron.doubleerror'}},$questnum);   push(@{$record{'scantron.doubleerror'}},$questnum);
  $record{"scantron.$questnum.answer"}='';   for (my $ans = 0; $ans < $answers_needed; $ans++) {
       my $bubble = substr($currentquest, $ans, 1);
       if ($bubble =~ /\d/) {
    $record{"scantron.$ansnum.answer"} = $alphabet[$bubble];
       } else {
    $record{"scantron.$ansnum.answer"}=' ';
       }
       $ansnum++;
    }
   
     } elsif (!defined($currentquest)      } elsif (!defined($currentquest)
      || $currentquest eq $$scantron_config{'Qoff'}        || (&occurence_count($currentquest,$$scantron_config{'Qoff'}) == length($currentquest)) 
      || $currentquest !~ /^\d$/) {       || (&occurence_count($currentquest, '\d') == 0)) {
  $record{"scantron.$questnum.answer"}='';   for (my $ans = 0; $ans < $answers_needed; $ans++ ) {
       $record{"scantron.$ansnum.answer"}='';
       $ansnum++;
   
    }
  if (!&scan_data($scan_data,"$whichline.no_bubble.$questnum")) {   if (!&scan_data($scan_data,"$whichline.no_bubble.$questnum")) {
     push(@{$record{"scantron.missingerror"}},$questnum);      push(@{$record{"scantron.missingerror"}},$questnum);
       $ansnum += $answers_needed;
  }   }
   
     } else {      } else {
  # wrap zero back to J   $currentquest = &digits_to_letters($currentquest);
  if ($currentquest eq '0') {   for (my $ans =0; $ans < $answers_needed; $ans++) {
     $record{"scantron.$questnum.answer"}=      $record{"scantron.$ansnum.answer"} = substr($currentquest, $ans, 1);
  $alphabet[9];      $ansnum++;
  } else {  
     $record{"scantron.$questnum.answer"}=  
  $alphabet[$currentquest-1];  
  }   }
     }      }
  } else {   } else {
   
       # Otherwise there's a positional notation;
       # each bubble line requires Qlength items, and there are filled in
       # bubbles for each case where there 'Qon' characters.
       #
   
     my @array=split($$scantron_config{'Qon'},$currentquest,-1);      my @array=split($$scantron_config{'Qon'},$currentquest,-1);
     if (length($array[0]) eq $$scantron_config{'Qlength'}) {  
  $record{"scantron.$questnum.answer"}='';      # If the split only  giveas us one element.. the full length of the
       # answser string, no bubbles are filled in:
   
       if (length($array[0]) eq $$scantron_config{'Qlength'}*$answers_needed) {
    for (my $ans = 0; $ans < $answers_needed; $ans++ ) {
       $record{"scantron.$ansnum.answer"}='';
       $ansnum++;
   
    }
  if (!&scan_data($scan_data,"$whichline.no_bubble.$questnum")) {   if (!&scan_data($scan_data,"$whichline.no_bubble.$questnum")) {
     push(@{$record{"scantron.missingerror"}},$questnum);      push(@{$record{"scantron.missingerror"}},$questnum);
  }   }
     } else {      } elsif (scalar(@array) lt 2) {
  $record{"scantron.$questnum.answer"}=  
     $alphabet[length($array[0])];   my $location      = length($array[0]);
    my $line_num      = $location / $$scantron_config{'Qlength'};
    my $bubble        = $alphabet[$location % $$scantron_config{'Qlength'}];
   
    for (my $ans = 0; $ans < $answers_needed; $ans++) {
       if ($ans eq $line_num) {
    $record{"scantron.$ansnum.answer"} = $bubble;
       } else {
    $record{"scantron.$ansnum.answer"} = ' ';
       }
       $ansnum++;
    }
     }      }
     if (scalar(@array) gt 2) {      #  If there's more than one instance of a bubble character
       #  That's a double bubble; with positional notation we can
       #  record all the bubbles filled in as well as the 
       #  fact this response consists of multiple bubbles.
       #
       else {
  push(@{$record{'scantron.doubleerror'}},$questnum);   push(@{$record{'scantron.doubleerror'}},$questnum);
   
    my $first_answer = $ansnum;
    for (my $ans =0; $ans < $answers_needed; $ans++) {
       my $item = $first_answer+$ans;
       $record{"scantron.$item.answer"} = '';
    }
   
  my @ans=@array;   my @ans=@array;
  my $i=length($ans[0]);shift(@ans);   my $i=0;
    my $increment = 0;
  while ($#ans) {   while ($#ans) {
     $i+=length($ans[0])+1;      $i+=length($ans[0]) + $increment;
     $record{"scantron.$questnum.answer"}.=$alphabet[$i];      my $line   = int($i/$$scantron_config{'Qlength'} + $first_answer);
       my $bubble = $i%$$scantron_config{'Qlength'};
       $record{"scantron.$line.answer"}.=$alphabet[$bubble];
     shift(@ans);      shift(@ans);
       $increment = 1;
  }   }
    $ansnum += $answers_needed;
     }      }
  }   }
     }      }
Line 5545  sub scantron_form_start { Line 5807  sub scantron_form_start {
   <input type="hidden" name="scantron_options_ignore" value="$env{'form.scantron_options_ignore'}" />    <input type="hidden" name="scantron_options_ignore" value="$env{'form.scantron_options_ignore'}" />
   <input type="hidden" name="scantron_options_hidden" value="$env{'form.scantron_options_hidden'}" />    <input type="hidden" name="scantron_options_hidden" value="$env{'form.scantron_options_hidden'}" />
 SCANTRONFORM  SCANTRONFORM
   
     my $line = 0;
       while (defined($env{"form.scantron.bubblelines.$line"})) {
          my $chunk =
      '<input type="hidden" name="scantron.bubblelines.'.$line.'" value="'.$env{"form.scantron.bubblelines.$line"}.'" />'."\n";
          $chunk .=
      '<input type="hidden" name="scantron.first_bubble_line.'.$line.'" value="'.$env{"form.scantron.first_bubble_line.$line"}.'" />'."\n";
          $result .= $chunk;
          $line++;
      }
     return $result;      return $result;
 }  }
   
Line 5603  sub scantron_validate_file { Line 5875  sub scantron_validate_file {
     }      }
     my $currentphase=$env{'form.validatepass'};      my $currentphase=$env{'form.validatepass'};
   
   
     my $stop=0;      my $stop=0;
     while (!$stop && $currentphase < scalar(@validate_phases)) {      while (!$stop && $currentphase < scalar(@validate_phases)) {
  $r->print("<p> Validating ".$validate_phases[$currentphase]."</p>");   $r->print("<p> Validating ".$validate_phases[$currentphase]."</p>");
Line 6026  sub scantron_validate_ID { Line 6299  sub scantron_validate_ID {
     #get scantron line setup      #get scantron line setup
     my %scantron_config=&get_scantron_config($env{'form.scantron_format'});      my %scantron_config=&get_scantron_config($env{'form.scantron_format'});
     my ($scanlines,$scan_data)=&scantron_getfile();      my ($scanlines,$scan_data)=&scantron_getfile();
       
       &scantron_get_maxbubble(); # parse needs the bubble_lines.. array.
   
     my %found=('ids'=>{},'usernames'=>{});      my %found=('ids'=>{},'usernames'=>{});
     for (my $i=0;$i<=$scanlines->{'count'};$i++) {      for (my $i=0;$i<=$scanlines->{'count'};$i++) {
Line 6111  sub scantron_validate_ID { Line 6386  sub scantron_validate_ID {
 sub scantron_get_correction {  sub scantron_get_correction {
     my ($r,$i,$scan_record,$scan_config,$line,$error,$arg)=@_;      my ($r,$i,$scan_record,$scan_config,$line,$error,$arg)=@_;
   
 #FIXME in the case of a duplicated ID the previous line, probaly need  #FIXME in the case of a duplicated ID the previous line, probably need
 #to show both the current line and the previous one and allow skipping  #to show both the current line and the previous one and allow skipping
 #the previous one or the current one  #the previous one or the current one
   
Line 6210  ENDSCRIPT Line 6485  ENDSCRIPT
  $r->print($message);   $r->print($message);
  $r->print("<p>Please indicate which bubble should be used for grading</p>");   $r->print("<p>Please indicate which bubble should be used for grading</p>");
  foreach my $question (@{$arg}) {   foreach my $question (@{$arg}) {
     my $selected=$$scan_record{"scantron.$question.answer"};      my $selected  = &get_response_bubbles($scan_record, $question);
       my @select_array = split(/:/,$selected);
     &scantron_bubble_selector($r,$scan_config,$question,      &scantron_bubble_selector($r,$scan_config,$question,
       split('',$selected));        @select_array);
  }   }
     } elsif ($error eq 'missingbubble') {      } elsif ($error eq 'missingbubble') {
  $r->print("<p>There have been <b>no</b> bubbles scanned for some question(s)</p>\n");   $r->print("<p>There have been <b>no</b> bubbles scanned for some question(s)</p>\n");
Line 6222  ENDSCRIPT Line 6498  ENDSCRIPT
  $r->print('<input type="hidden" name="scantron_questions" value="'.   $r->print('<input type="hidden" name="scantron_questions" value="'.
   join(',',@{$arg}).'" />');    join(',',@{$arg}).'" />');
  foreach my $question (@{$arg}) {   foreach my $question (@{$arg}) {
     my $selected=$$scan_record{"scantron.$question.answer"};      my $selected = &get_response_bubbles($scan_record, $question);
     &scantron_bubble_selector($r,$scan_config,$question);      my @select_array = split(/:/,$selected); # ought to be an array of empties.
       &scantron_bubble_selector($r,$scan_config,$question, @select_array);
  }   }
     } else {      } else {
  $r->print("\n<ul>");   $r->print("\n<ul>");
Line 6243  ENDSCRIPT Line 6520  ENDSCRIPT
     $r           - Apache request object      $r           - Apache request object
     $scan_config - hash from &get_scantron_config()      $scan_config - hash from &get_scantron_config()
     $quest       - number of the bubble line to make a corrector for      $quest       - number of the bubble line to make a corrector for
     $selected    - array of letters of previously selected bubbles      @lines       - array of answer lines.
     $lines       - if present, number of bubble lines to show  
   
 =cut  =cut
   
 sub scantron_bubble_selector {  sub scantron_bubble_selector {
     my ($r,$scan_config,$quest,@selected, $lines)=@_;      my ($r,$scan_config,$quest,@lines)=@_;
     my $max=$$scan_config{'Qlength'};      my $max=$$scan_config{'Qlength'};
   
   
     my $scmode=$$scan_config{'Qon'};      my $scmode=$$scan_config{'Qon'};
   
       my $bubble_length = scalar(@lines);
   
   
     if ($scmode eq 'number' || $scmode eq 'letter') { $max=10; }           if ($scmode eq 'number' || $scmode eq 'letter') { $max=10; }     
   
       my $response = $quest-1;
       my $lines = $bubble_lines_per_response{$response};
   
     if (!defined($lines)) {  
  $lines = 1;  
     }  
     my $total_lines = $lines*2;      my $total_lines = $lines*2;
     my @alphabet=('A'..'Z');      my @alphabet=('A'..'Z');
     $r->print("<table border='1'><tr><td rowspan='".$total_lines."'>$quest</td>");      $r->print("<table border='1'><tr><td rowspan='".$total_lines."'>$quest</td>");
Line 6267  sub scantron_bubble_selector { Line 6547  sub scantron_bubble_selector {
  if ($l != 0) {   if ($l != 0) {
     $r->print('<tr>');      $r->print('<tr>');
  }   }
    my @selected = split(//,$lines[$l]);
  # FIXME:  This loop probably has to be considerably more clever for  
  #  multiline bubbles: User can multibubble by having bubbles in  
  #  several lines.  User can skip lines legitimately etc. etc.  
   
  for (my $i=0;$i<$max;$i++) {   for (my $i=0;$i<$max;$i++) {
     $r->print("\n".'<td align="center">');      $r->print("\n".'<td align="center">');
     if ($selected[0] eq $alphabet[$i]) {       if ($selected[0] eq $alphabet[$i]) { 
Line 6432  sub scantron_validate_CODE { Line 6708  sub scantron_validate_CODE {
   
     my %allcodes=&get_codes();      my %allcodes=&get_codes();
   
       &scantron_get_maxbubble(); # parse needs the lines per response array.
   
     my ($scanlines,$scan_data)=&scantron_getfile();      my ($scanlines,$scan_data)=&scantron_getfile();
     for (my $i=0;$i<=$scanlines->{'count'};$i++) {      for (my $i=0;$i<=$scanlines->{'count'};$i++) {
  my $line=&scantron_get_line($scanlines,$scan_data,$i);   my $line=&scantron_get_line($scanlines,$scan_data,$i);
Line 6484  sub scantron_validate_doublebubble { Line 6762  sub scantron_validate_doublebubble {
     #get scantron line setup      #get scantron line setup
     my %scantron_config=&get_scantron_config($env{'form.scantron_format'});      my %scantron_config=&get_scantron_config($env{'form.scantron_format'});
     my ($scanlines,$scan_data)=&scantron_getfile();      my ($scanlines,$scan_data)=&scantron_getfile();
   
       &scantron_get_maxbubble(); # parse needs the bubble line array.
   
     for (my $i=0;$i<=$scanlines->{'count'};$i++) {      for (my $i=0;$i<=$scanlines->{'count'};$i++) {
  my $line=&scantron_get_line($scanlines,$scan_data,$i);   my $line=&scantron_get_line($scanlines,$scan_data,$i);
  if ($line=~/^[\s\cz]*$/) { next; }   if ($line=~/^[\s\cz]*$/) { next; }
Line 6507  sub scantron_validate_doublebubble { Line 6788  sub scantron_validate_doublebubble {
    resource and then checking &Apache::lonxml::get_problem_counter()     resource and then checking &Apache::lonxml::get_problem_counter()
    for what the current value of the problem counter is.     for what the current value of the problem counter is.
   
    Caches the result to $env{'form.scantron_maxbubble'}     Caches the results to $env{'form.scantron_maxbubble'},
      $env{'form.scantron.bubble_lines.n'} and 
      $env{'form.scantron.first_bubble_line.n'}
      which are the total number of bubble, lines, the number of bubble
      lines for reponse n and number of the first bubble line for response n.
   
 =cut  =cut
   
 sub scantron_get_maxbubble {      sub scantron_get_maxbubble {    
   
     if (defined($env{'form.scantron_maxbubble'}) &&      if (defined($env{'form.scantron_maxbubble'}) &&
  $env{'form.scantron_maxbubble'}) {   $env{'form.scantron_maxbubble'}) {
    &restore_bubble_lines();
  return $env{'form.scantron_maxbubble'};   return $env{'form.scantron_maxbubble'};
     }      }
   
     my $navmap=Apache::lonnavmaps::navmap->new();      my (undef, undef, $sequence) =
     my (undef,undef,$sequence)=  
  &Apache::lonnet::decode_symb($env{'form.selectpage'});   &Apache::lonnet::decode_symb($env{'form.selectpage'});
   
       my $navmap=Apache::lonnavmaps::navmap->new();
     my $map=$navmap->getResourceByUrl($sequence);      my $map=$navmap->getResourceByUrl($sequence);
     my @resources=$navmap->retrieveResources($map,\&scantron_filter,1,0);      my @resources=$navmap->retrieveResources($map,\&scantron_filter,1,0);
   
Line 6532  sub scantron_get_maxbubble { Line 6817  sub scantron_get_maxbubble {
     my $cid         = $env{'request.course.id'};      my $cid         = $env{'request.course.id'};
     my $total_lines = 0;      my $total_lines = 0;
     %bubble_lines_per_response = ();      %bubble_lines_per_response = ();
       %first_bubble_line         = ();
   
     
       my $response_number = 0;
       my $bubble_line     = 0;
     foreach my $resource (@resources) {      foreach my $resource (@resources) {
  my $symb = $resource->symb();   my $symb = $resource->symb();
    &Apache::lonxml::clear_bubble_lines_for_part();
  my $result=&Apache::lonnet::ssi($resource->src(),   my $result=&Apache::lonnet::ssi($resource->src(),
  ('symb' => $resource->symb()),   ('symb' => $resource->symb()),
  ('grade_target' => 'analyze'),   ('grade_target' => 'analyze'),
Line 6549  sub scantron_get_maxbubble { Line 6839  sub scantron_get_maxbubble {
   
   
  foreach my $part_id (@{$analysis{'parts'}}) {   foreach my $part_id (@{$analysis{'parts'}}) {
     my $bubble_lines = $analysis{"$part_id.bubble_lines"}[0];  
     if (!$bubble_lines) {  
  $bubble_lines = 1;      my $lines = $analysis{"$part_id.bubble_lines"};;
     }  
     $bubble_lines_per_response{"$symb.$part_id"} = $bubble_lines;      # TODO - make this a persistent hash not an array.
     $total_lines = $total_lines + $bubble_lines;  
   
       $first_bubble_line{$response_number}           = $bubble_line;
       $bubble_lines_per_response{$response_number}   = $lines;
       $response_number++;
   
       $bubble_line +=  $lines;
       $total_lines +=  $lines;
  }   }
   
     }      }
     &Apache::lonnet::delenv('scantron\.');      &Apache::lonnet::delenv('scantron\.');
   
       &save_bubble_lines();
     $env{'form.scantron_maxbubble'} =      $env{'form.scantron_maxbubble'} =
  $total_lines;   $total_lines;
     return $env{'form.scantron_maxbubble'};      return $env{'form.scantron_maxbubble'};
Line 6569  sub scantron_get_maxbubble { Line 6868  sub scantron_get_maxbubble {
 =item scantron_validate_missingbubbles  =item scantron_validate_missingbubbles
   
    Validates all scanlines in the selected file to not have any     Validates all scanlines in the selected file to not have any
    bubble lines with missing bubbles that haven't been verified as missing.      answers that don't have bubbles that have not been verified
       to be bubble free.
   
 =cut  =cut
   
Line 6591  sub scantron_validate_missingbubbles { Line 6891  sub scantron_validate_missingbubbles {
  $scan_data);   $scan_data);
  if (!defined($$scan_record{'scantron.missingerror'})) { next; }   if (!defined($$scan_record{'scantron.missingerror'})) { next; }
  my @to_correct;   my @to_correct;
   
    # Probably here's where the error is...
   
  foreach my $missing (@{$$scan_record{'scantron.missingerror'}}) {   foreach my $missing (@{$$scan_record{'scantron.missingerror'}}) {
     if ($missing > $max_bubble) { next; }      if ($missing > $max_bubble) { next; }
     push(@to_correct,$missing);      push(@to_correct,$missing);
Line 6663  SCANTRONFORM Line 6966  SCANTRONFORM
     my $start=&Time::HiRes::time();      my $start=&Time::HiRes::time();
     my $i=-1;      my $i=-1;
     my ($uname,$udom,$started);      my ($uname,$udom,$started);
   
       &scantron_get_maxbubble(); # Need the bubble lines array to parse.
   
     while ($i<$scanlines->{'count'}) {      while ($i<$scanlines->{'count'}) {
   ($uname,$udom)=('','');    ($uname,$udom)=('','');
   $i++;    $i++;
Line 6713  SCANTRONFORM Line 7019  SCANTRONFORM
     }      }
     my $result=&Apache::lonnet::ssi($resource->src(),%form);      my $result=&Apache::lonnet::ssi($resource->src(),%form);
     if ($result ne '') {      if ($result ne '') {
  &Apache::lonnet::logthis("scantron grading error -> $result");  
  &Apache::lonnet::logthis("scantron grading error info name $uname domain $udom course $env{'request.course.id'} url ".$resource->src());  
     }      }
     if (&Apache::loncommon::connection_aborted($r)) { last; }      if (&Apache::loncommon::connection_aborted($r)) { last; }
  }   }
Line 6939  sub savedState { Line 7243  sub savedState {
     return \%savedState;      return \%savedState;
 }  }
   
 #--- Displays the main menu page -------  sub grading_menu {
 sub gradingmenu {      my ($request) = @_;
       my ($symb)=&get_symb($request);
       if (!$symb) {return '';}
       my $probTitle = &Apache::lonnet::gettitle($symb);
       my ($table,undef,$hdgrade) = &showResourceInfo($symb,$probTitle);
   
       $request->print($table);
       my %fields = ('symb'=>&Apache::lonenc::check_encrypt($symb),
                     'handgrade'=>$hdgrade,
                     'probTitle'=>$probTitle,
                     'command'=>'submit_options',
                     'saveState'=>"",
                     'gradingMenu'=>1,
                     'showgrading'=>"yes");
       my $url = &Apache::lonhtmlcommon::build_url('grades/',\%fields);
       my @menu = ({ url => $url,
                        name => &mt('Manual Grading/View Submissions'),
                        short_description => 
       &mt('Start the process of hand grading submissions.'),
                    });
       $fields{'command'} = 'csvform';
       $url = &Apache::lonhtmlcommon::build_url('grades/',\%fields);
       push (@menu, { url => $url,
                      name => &mt('Upload Scores'),
                      short_description => 
               &mt('Specify a file containing the class scores for current resource.')});
       $fields{'command'} = 'processclicker';
       $url = &Apache::lonhtmlcommon::build_url('grades/',\%fields);
       push (@menu, { url => $url,
                      name => &mt('Process Clicker'),
                      short_description => 
               &mt('Specify a file containing the clicker information for this resource.')});
       $fields{'command'} = 'scantron_selectphase';
       $url = &Apache::lonhtmlcommon::build_url('grades/',\%fields);
       push (@menu, { url => $url,
                      name => &mt('Grade/Manage Scantron Forms'),
                      short_description => 
               &mt('')});
       $fields{'command'} = 'verify';
       $url = &Apache::lonhtmlcommon::build_url('grades/',\%fields);
       push (@menu, { url => "",
                      name => &mt('Verify Receipt'),
                      short_description => 
               &mt('')});
       #
       # Create the menu
       my $Str;
       # $Str .= '<h2>'.&mt('Please select a grading task').'</h2>';
       $Str .= '<form method="post" action="" name="gradingMenu">';
       $Str .= '<input type="hidden" name="command" value="" />'.
       '<input type="hidden" name="symb"        value="'.&Apache::lonenc::check_encrypt($symb).'" />'."\n".
    '<input type="hidden" name="handgrade"   value="'.$hdgrade.'" />'."\n".
    '<input type="hidden" name="probTitle"   value="'.$probTitle.'" />'."\n".
    '<input type="hidden" name="saveState"   value="" />'."\n".
    '<input type="hidden" name="gradingMenu" value="1" />'."\n".
    '<input type="hidden" name="showgrading" value="yes" />'."\n";
   
       foreach my $menudata (@menu) {
           if ($menudata->{'name'} ne &mt('Verify Receipt')) {
               $Str .='    <h3><a '.
                   $menudata->{'jscript'}.
                   ' href="'.
                   $menudata->{'url'}.'" >'.
                   $menudata->{'name'}."</a></h3>\n";
           } else {
               $Str .='    <h3><input type="button" value="Verify Receipt" '.
                   $menudata->{'jscript'}.
                   ' onClick="javascript:checkChoice(document.forms.gradingMenu,\'5\',\'verify\')" '.
                   ' /></h3>';
               $Str .= ('&nbsp;'x8).
                       ' receipt: '.&Apache::lonnet::recprefix($env{'request.course.id'}).
                       '-<input type="text" name="receipt" size="4" onChange="javascript:checkReceiptNo(this.form,\'OK\')" />';
           }
           $Str .= '    '.('&nbsp;'x8).$menudata->{'short_description'}.
               "\n";
       }
       $Str .="</form>\n";
       $request->print(<<GRADINGMENUJS);
   <script type="text/javascript" language="javascript">
       function checkChoice(formname,val,cmdx) {
    if (val <= 2) {
       var cmd = radioSelection(formname.radioChoice);
       var cmdsave = cmd;
    } else {
       cmd = cmdx;
       cmdsave = 'submission';
    }
    formname.command.value = cmd;
    if (val < 5) formname.submit();
    if (val == 5) {
       if (!checkReceiptNo(formname,'notOK')) { 
           return false;
       } else {
           formname.submit();
       }
    }
       }
   
       function checkReceiptNo(formname,nospace) {
    var receiptNo = formname.receipt.value;
    var checkOpt = false;
    if (nospace == "OK" && isNaN(receiptNo)) {checkOpt = true;}
    if (nospace == "notOK" && (isNaN(receiptNo) || receiptNo == "")) {checkOpt = true;}
    if (checkOpt) {
       alert("Please enter a receipt number given by a student in the receipt box.");
       formname.receipt.value = "";
       formname.receipt.focus();
       return false;
    }
    return true;
       }
   </script>
   GRADINGMENUJS
       &commonJSfunctions($request);
       return $Str;    
   }
   
   
   #--- Displays the submissions first page -------
   sub submit_options {
     my ($request) = @_;      my ($request) = @_;
     my ($symb)=&get_symb($request);      my ($symb)=&get_symb($request);
     if (!$symb) {return '';}      if (!$symb) {return '';}
Line 6983  sub gradingmenu { Line 7406  sub gradingmenu {
 </script>  </script>
 GRADINGMENUJS  GRADINGMENUJS
     &commonJSfunctions($request);      &commonJSfunctions($request);
     my $result='<h3>&nbsp;<span class="LC_info">Manual Grading/View Submission</span></h3>';  
     my ($table,undef,$hdgrade) = &showResourceInfo($symb,$probTitle);      my ($table,undef,$hdgrade) = &showResourceInfo($symb,$probTitle);
     $result.=$table;      my $result;
     my (undef,$sections) = &getclasslist('all','0');      my (undef,$sections) = &getclasslist('all','0');
     my $savedState = &savedState();      my $savedState = &savedState();
     my $saveCmd = ($$savedState{'saveCmd'} eq '' ? 'submission' : $$savedState{'saveCmd'});      my $saveCmd = ($$savedState{'saveCmd'} eq '' ? 'submission' : $$savedState{'saveCmd'});
Line 7002  GRADINGMENUJS Line 7424  GRADINGMENUJS
  '<input type="hidden" name="gradingMenu" value="1" />'."\n".   '<input type="hidden" name="gradingMenu" value="1" />'."\n".
  '<input type="hidden" name="showgrading" value="yes" />'."\n";   '<input type="hidden" name="showgrading" value="yes" />'."\n";
   
     $result.='<table width="100%" border="0"><tr><td bgcolor=#777777>'."\n".      $result.='
  '<table width="100%" border="0"><tr bgcolor="#e6ffff"><td colspan="2">'."\n".      <div class="LC_grade_select_mode">
  '&nbsp;<b>Select a Grading/Viewing Option</b></td></tr>'."\n".        <div class="LC_grade_select_mode_current">
  '<tr bgcolor="#ffffe6" valign="top"><td>'."\n";          <h2>
             '.&mt('Grade Current Resource').'
     $result.='<table width="100%" border="0">';          </h2>
     $result.='<tr bgcolor="#ffffe6" valign="top"><td>'."\n".          <div class="LC_grade_select_mode_body">
  '&nbsp;'.&mt('Select Section').': <select name="section" multiple="multiple" size="3">'."\n";            <div class="LC_grades_resource_info">
              '.$table.'
             </div>
             <div class="LC_grade_select_mode_selector">
                <div class="LC_grade_select_mode_selector_header">
                   '.&mt('Sections').'
                </div>
                <div class="LC_grade_select_mode_selector_body">
          <select name="section" multiple="multiple" size="5">'."\n";
     if (ref($sections)) {      if (ref($sections)) {
  foreach (sort (@$sections)) {   foreach my $section (sort (@$sections)) {
     $result.='<option value="'.$_.'" '.      $result.='<option value="'.$section.'" '.
  ($saveSec eq $_ ? 'selected="selected"':'').'>'.$_.'</option>'."\n";   ($saveSec eq $section ? 'selected="selected"':'').'>'.$section.'</option>'."\n";
  }   }
     }      }
     $result.= '<option value="all" '.($saveSec eq 'all' ? 'selected="selected"' : ''). '>all</option></select> &nbsp; ';      $result.= '<option value="all" '.($saveSec eq 'all' ? 'selected="selected"' : ''). '>all</option></select> &nbsp; ';
       $result.='
     $result.=&mt('Student Status').':'.&Apache::lonhtmlcommon::StatusOptions($saveStatus,undef,1,undef);               </div>
             </div>
     $result.='</td></tr>';            <div class="LC_grade_select_mode_selector">
                <div class="LC_grade_select_mode_selector_header">
     $result.='<tr bgcolor="#ffffe6"valign="top"><td><label>'.                  '.&mt('Groups').'
  '<input type="radio" name="radioChoice" value="submission" '.               </div>
  ($saveCmd eq 'submission' ? 'checked="checked"' : '').' /> '.'<b>'.&mt('Current Resource').':</b> '.&mt('For one or more students').               <div class="LC_grade_select_mode_selector_body">
  '</label> <select name="submitonly">'.                  '.&Apache::lonstatistics::GroupSelect('group','multiple',5).'
  '<option value="yes" '.               </div>
  ($saveSub eq 'yes' ? 'selected="selected"' : '').'>'.&mt('with submissions').'</option>'.            </div>
  '<option value="queued" '.            <div class="LC_grade_select_mode_selector">
  ($saveSub eq 'queued' ? 'selected="selected"' : '').'>'.&mt('in grading queue').'</option>'.               <div class="LC_grade_select_mode_selector_header">
  '<option value="graded" '.                  '.&mt('Access Status').'
  ($saveSub eq 'graded' ? 'selected="selected"' : '').'>'.&mt('with ungraded submissions').'</option>'.               </div>
  '<option value="incorrect" '.               <div class="LC_grade_select_mode_selector_body">
  ($saveSub eq 'incorrect' ? 'selected="selected"' : '').'>'.&mt('with incorrect submissions').'</option>'.                  '.&Apache::lonhtmlcommon::StatusOptions($saveStatus,undef,5,undef,'mult').'
  '<option value="all" '.               </div>
  ($saveSub eq 'all' ? 'selected="selected"' : '').'>'.&mt('with any status').'</option></select></td></tr>'."\n";            </div>
             <div class="LC_grade_select_mode_selector">
     $result.='<tr bgcolor="#ffffe6"valign="top"><td>'.               <div class="LC_grade_select_mode_selector_header">
  '<label><input type="radio" name="radioChoice" value="viewgrades" '.                  '.&mt('Submission Status').'
  ($saveCmd eq 'viewgrades' ? 'checked="checked"' : '').' /> '.               </div>
  '<b>Current Resource:</b> For all students in selected section or course</label></td></tr>'."\n";               <div class="LC_grade_select_mode_selector_body">
                  <select name="submitonly" size="5">
     $result.='<tr bgcolor="#ffffe6" valign="top"><td>'.           <option value="yes" '.      ($saveSub eq 'yes'       ? 'selected="selected"' : '').'>'.&mt('with submissions').'</option>
  '<label><input type="radio" name="radioChoice" value="pickStudentPage" '.           <option value="queued" '.   ($saveSub eq 'queued'    ? 'selected="selected"' : '').'>'.&mt('in grading queue').'</option>
  ($saveCmd eq 'pickStudentPage' ? 'checked="checked"' : '').' /> '.           <option value="graded" '.   ($saveSub eq 'graded'    ? 'selected="selected"' : '').'>'.&mt('with ungraded submissions').'</option>
  'The <b>complete</b> set/page/sequence: For one student</label></td></tr>'."\n";           <option value="incorrect" '.($saveSub eq 'incorrect' ? 'selected="selected"' : '').'>'.&mt('with incorrect submissions').'</option>
                    <option value="all" '.      ($saveSub eq 'all'       ? 'selected="selected"' : '').'>'.&mt('with any status').'</option>
     $result.='<tr bgcolor="#ffffe6"><td><br />'.                 </select>
  '<input type="button" onClick="javascript:checkChoice(this.form,\'2\');" value="Next->" />'.               </div>
  '</td></tr></table>'."\n";            </div>
             <div class="LC_grade_select_mode_type_body">
     $result.='</td><td valign="top">';              <div class="LC_grade_select_mode_type">
                 <label>
     $result.='<table width="100%" border="0">';                  <input type="radio" name="radioChoice" value="submission" '.
     $result.='<tr bgcolor="#ffffe6"><td>'.                    ($saveCmd eq 'submission' ? 'checked="checked"' : '').' /> '.
  '<input type="button" onClick="javascript:checkChoice(this.form,\'3\',\'csvform\');" value="'.&mt('Upload').'" />'.               &mt('Select individual students to grade and view submissions.').'
  ' '.&mt('scores from file').' </td></tr>'."\n";        </label> 
               </div>
     $result.='<tr bgcolor="#ffffe6"><td>'.              <div class="LC_grade_select_mode_type">
         '<input type="button" onClick="javascript:checkChoice(this.form,\'6\',\'processclicker\');" value="'.&mt('Process').'" />'.        <label>
         ' '.&mt('clicker file').' </td></tr>'."\n";                  <input type="radio" name="radioChoice" value="viewgrades" '.
                     ($saveCmd eq 'viewgrades' ? 'checked="checked"' : '').' /> '.
     $result.='<tr bgcolor="#ffffe6"valign="top"><td colspan="2">'.                      &mt('Grade all selected students in a grading table.').'
  '<input type="button" onClick="javascript:checkChoice(this.form,\'4\',\'scantron_selectphase\');'.                </label>
  '" value="'.&mt('Grade').'" /> scantron forms</td></tr>'."\n";              </div>
               <div class="LC_grade_select_mode_type">
     if ((&Apache::lonnet::allowed('mgr',$env{'request.course.id'})) && ($symb)) {        <input type="button" onClick="javascript:checkChoice(this.form,\'2\');" value="'.&mt('Next-&gt;').'" />
  $result.='<tr bgcolor="#ffffe6"valign="top"><td>'.              </div>
     '<input type="button" onClick="javascript:checkChoice(this.form,\'5\',\'verify\');" value="'.&mt('Verify').'" />'.            </div>
     ' '.&mt('receipt').': '.          </div>
     &Apache::lonnet::recprefix($env{'request.course.id'}).        </div>
     '-<input type="text" name="receipt" size="4" onChange="javascript:checkReceiptNo(this.form,\'OK\')" />'.        <div class="LC_grade_select_mode_page">
     '</td></tr>'."\n";          <h2>
     }            '.&mt('Grade Complete Folder for One Student').'
     $result.='<tr bgcolor="#ffffe6"valign="top"><td colspan="2">'.          </h2>
  '<input type="button" onClick="javascript:this.form.action=\'/adm/helper/resettimes.helper\';this.form.submit();'.          <div class="LC_grades_select_mode_body">
  '" value="'.&mt('Manage').'" /> access times.</td></tr>'."\n";            <div class="LC_grade_select_mode_type_body">
     $result.='<tr bgcolor="#ffffe6"valign="top"><td colspan="2">'.              <div class="LC_grade_select_mode_type">
  '<input type="button" onClick="javascript:this.form.command.value=\'codelist\';this.form.action=\'/adm/pickcode\';this.form.submit();'.                <label>
  '" value="'.&mt('View').'" /> saved CODEs.</td></tr>'."\n";                  <input type="radio" name="radioChoice" value="pickStudentPage" '.
     ($saveCmd eq 'pickStudentPage' ? 'checked="checked"' : '').' /> '.
     $result.='</table>'."\n".    &mt('The <b>complete</b> page/sequence/folder: For one student').'
  '</td></tr></table>'."\n".                </label>
  '</td></tr></table></form>'."\n";              </div>
               <div class="LC_grade_select_mode_type">
         <input type="button" onClick="javascript:checkChoice(this.form,\'2\');" value="'.&mt('Next-&gt;').'" />
               </div>
             </div>
           </div>
         </div>
       </div>
     </form>';
     return $result;      return $result;
 }  }
   
Line 7257  function sanitycheck() { Line 7695  function sanitycheck() {
 <input type="hidden" name="saveState"  value="$env{'form.saveState'}" />  <input type="hidden" name="saveState"  value="$env{'form.saveState'}" />
 <input type="file" name="upfile" size="50" />  <input type="file" name="upfile" size="50" />
 <br /><label>$type: $selectform</label>  <br /><label>$type: $selectform</label>
 <br /><label>$attendance: <input type="radio" name="gradingmechanism" value="attendance" $checked{'attendance'} onClick="sanitycheck()" /></label>  <br /><label><input type="radio" name="gradingmechanism" value="attendance" $checked{'attendance'} onClick="sanitycheck()" />$attendance </label>
 <br /><label>$personnel: <input type="radio" name="gradingmechanism" value="personnel" $checked{'personnel'} onClick="sanitycheck()" /></label>  <br /><label><input type="radio" name="gradingmechanism" value="personnel" $checked{'personnel'} onClick="sanitycheck()" />$personnel</label>
 <br /><label>$specific: <input type="radio" name="gradingmechanism" value="specific" $checked{'specific'} onClick="sanitycheck()" /></label>  <br /><label><input type="radio" name="gradingmechanism" value="specific" $checked{'specific'} onClick="sanitycheck()" />$specific </label>
 <input type="text" name="specificid" value="$env{'form.specificid'}" size="20" />  <input type="text" name="specificid" value="$env{'form.specificid'}" size="20" />
 <input type="hidden" name="waschecked" value="$env{'form.gradingmechanism'}" />  <input type="hidden" name="waschecked" value="$env{'form.gradingmechanism'}" />
 <br /><label>$pcorrect: <input type="text" name="pcorrect" size="4" value="$env{'form.pcorrect'}" onChange="sanitycheck()" /></label>  <br /><label>$pcorrect: <input type="text" name="pcorrect" size="4" value="$env{'form.pcorrect'}" onChange="sanitycheck()" /></label>
Line 7362  ENDHEADER Line 7800  ENDHEADER
     }      }
     $result.='<br />'.&mt('Found [_1] question(s)',$number).'<br />'.      $result.='<br />'.&mt('Found [_1] question(s)',$number).'<br />'.
              '<input type="hidden" name="number" value="'.$number.'" />'.               '<input type="hidden" name="number" value="'.$number.'" />'.
                &mt('Awarding [_1] percent for corrion(s)',$number).'<br />'.
                '<input type="hidden" name="number" value="'.$number.'" />'.
              &mt('Awarding [_1] percent for correct and [_2] percent for incorrect responses',               &mt('Awarding [_1] percent for correct and [_2] percent for incorrect responses',
                  $env{'form.pcorrect'},$env{'form.pincorrect'}).                   $env{'form.pcorrect'},$env{'form.pincorrect'}).
              '<br />';               '<br />';
Line 7592  ENDHEADER Line 8032  ENDHEADER
   
 sub handler {  sub handler {
     my $request=$_[0];      my $request=$_[0];
   
     &reset_caches();      &reset_caches();
     if ($env{'browser.mathml'}) {      if ($env{'browser.mathml'}) {
  &Apache::loncommon::content_type($request,'text/xml');   &Apache::loncommon::content_type($request,'text/xml');
Line 7605  sub handler { Line 8044  sub handler {
     my $symb=&get_symb($request,1);      my $symb=&get_symb($request,1);
     my @commands=&Apache::loncommon::get_env_multiple('form.command');      my @commands=&Apache::loncommon::get_env_multiple('form.command');
     my $command=$commands[0];      my $command=$commands[0];
   
     if ($#commands > 0) {      if ($#commands > 0) {
  &Apache::lonnet::logthis("grades got multiple commands ".join(':',@commands));   &Apache::lonnet::logthis("grades got multiple commands ".join(':',@commands));
     }      }
   
   
     $request->print(&Apache::loncommon::start_page('Grading'));      $request->print(&Apache::loncommon::start_page('Grading'));
     if ($symb eq '' && $command eq '') {      if ($symb eq '' && $command eq '') {
  if ($env{'user.adv'}) {   if ($env{'user.adv'}) {
Line 7648  sub handler { Line 8090  sub handler {
  } elsif ($command eq 'processGroup' && $perm{'vgr'}) {   } elsif ($command eq 'processGroup' && $perm{'vgr'}) {
     &processGroup($request);      &processGroup($request);
  } elsif ($command eq 'gradingmenu' && $perm{'vgr'}) {   } elsif ($command eq 'gradingmenu' && $perm{'vgr'}) {
     $request->print(&gradingmenu($request));      $request->print(&grading_menu($request));
    } elsif ($command eq 'submit_options' && $perm{'vgr'}) {
       $request->print(&submit_options($request));
  } elsif ($command eq 'viewgrades' && $perm{'vgr'}) {   } elsif ($command eq 'viewgrades' && $perm{'vgr'}) {
     $request->print(&viewgrades($request));      $request->print(&viewgrades($request));
  } elsif ($command eq 'handgrade' && $perm{'mgr'}) {   } elsif ($command eq 'handgrade' && $perm{'mgr'}) {

Removed from v.1.441  
changed lines
  Added in v.1.477


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>