--- loncom/interface/statistics/lonstudentassessment.pm	2006/02/27 02:25:44	1.130
+++ loncom/interface/statistics/lonstudentassessment.pm	2008/09/14 15:16:30	1.148
@@ -1,6 +1,6 @@
 # The LearningOnline Network with CAPA
 #
-# $Id: lonstudentassessment.pm,v 1.130 2006/02/27 02:25:44 bowersj2 Exp $
+# $Id: lonstudentassessment.pm,v 1.148 2008/09/14 15:16:30 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -50,16 +50,20 @@ Presents assessment data about a student
 package Apache::lonstudentassessment;
 
 use strict;
-use Apache::lonstatistics;
-use Apache::lonhtmlcommon;
+use Apache::lonstatistics();
+use Apache::lonhtmlcommon();
 use Apache::loncommon();
 use Apache::loncoursedata;
 use Apache::lonnet; # for logging porpoises
 use Apache::lonlocal;
-use Apache::grades;
+use Apache::grades();
+use Apache::lonmsgdisplay();
 use Time::HiRes;
 use Spreadsheet::WriteExcel;
 use Spreadsheet::WriteExcel::Utility();
+use lib '/home/httpd/lib/perl/';
+use LONCAPA;
+ 
 
 #######################################################
 #######################################################
@@ -146,6 +150,7 @@ sub BuildStudentAssessmentPage {
                                'chartoutputmode' => 'scalar',
                                'chartoutputdata' => 'scalar',
                                'Section' => 'array',
+                               'Groups' => 'array',
                                'StudentData' => 'array',
                                'Maps' => 'array');
     &Apache::loncommon::store_course_settings('chart',\%Saveable_Parameters);
@@ -313,14 +318,24 @@ the chart page.
 #######################################################
 sub CreateInterface {
     my $Str = '';
-    $Str .= &Apache::lonhtmlcommon::breadcrumbs(undef,'Chart');
+    $Str .= &Apache::lonhtmlcommon::breadcrumbs('Chart','Chart_Description:Chart_Sections:Chart_Student_Data:Chart_Enrollment_Status:Chart_Sequences:Chart_Output_Formats:Chart_Output_Data');
 #    $Str .= &CreateLegend();
     $Str .= '<table cellspacing="5">'."\n";
     $Str .= '<tr>';
-    $Str .= '<td align="center"><b>'.&mt('Sections').'</b></td>';
-    $Str .= '<td align="center"><b>'.&mt('Student Data</b>').'</td>';
-    $Str .= '<td align="center"><b>'.&mt('Enrollment Status').'</b></td>';
-    $Str .= '<td align="center"><b>'.&mt('Sequences and Folders').'</b></td>';
+    $Str .= '<td align="center"><b>'.&mt('Sections').'</b>'.
+	&Apache::loncommon::help_open_topic("Chart_Sections").
+	'</td>';
+    $Str .= '<td align="center"><b>'.&mt('Groups').'</b>'.
+	'</td>';
+    $Str .= '<td align="center"><b>'.&mt('Student Data</b>').
+	&Apache::loncommon::help_open_topic("Chart_Student_Data").
+	'</td>';
+    $Str .= '<td align="center"><b>'.&mt('Access Status').'</b>'.
+	&Apache::loncommon::help_open_topic("Chart_Enrollment_Status").
+	'</td>';
+    $Str .= '<td align="center"><b>'.&mt('Sequences and Folders').'</b>'.
+	&Apache::loncommon::help_open_topic("Chart_Sequences").
+	'</td>';
     $Str .= '<td align="center"><b>'.&mt('Output Format').'</b>'.
         &Apache::loncommon::help_open_topic("Chart_Output_Formats").
         '</td>';
@@ -332,6 +347,8 @@ sub CreateInterface {
     $Str .= '<tr><td align="center">'."\n";
     $Str .= &Apache::lonstatistics::SectionSelect('Section','multiple',5);
     $Str .= '</td><td align="center">';
+    $Str .= &Apache::lonstatistics::GroupSelect('Group','multiple',5);
+    $Str .= '</td><td align="center">';
     $Str .= &Apache::lonstatistics::StudentDataSelect('StudentData','multiple',
                                                       5,undef);
     $Str .= '</td><td>'."\n";
@@ -355,7 +372,7 @@ sub CreateInterface {
     $Str .= '&nbsp;'x5;
     $Str .= 
         &mt('Status [_1]',
-            '<input type="text" name="stats_status" size="60" value="" />');
+            '<input type="text" name="stats_status" size="60" value="" readonly="readonly" />');
     $Str .= '<br />';
     return $Str;
 }
@@ -650,12 +667,25 @@ sub html_initialize {
                   &mt('Unable to retrieve course information.').
                   '</h3>');
     }
+
+    # If we're showing links, show a checkbox to open in new
+    # windows.
+    if ($show_links ne 'no') {
+        my $labeltext = &mt('Show links in new window:');
+        $r->print(<<NEW_WINDOW_CHECKBOX);
+<script type="text/javascript">new_window = true;</script>
+<p><label>$labeltext 
+<input type="checkbox" checked="1" onclick="new_window=this.checked" />
+</label></p>
+NEW_WINDOW_CHECKBOX
+    }
+
     #
     $r->print("<h3>".$env{'course.'.$env{'request.course.id'}.'.description'}.
               "&nbsp;&nbsp;".localtime(time)."</h3>");
     #
     if ($chosen_output->{'base'} !~ /^final table/) {
-        $r->print("<h3>".$chosen_output->{'shortdesc'}."</h3>");        
+        $r->print("<h3>".&mt($chosen_output->{'shortdesc'})."</h3>");        
     }
     my $Str = "<pre>\n";
     # First, the @StudentData fields need to be listed
@@ -719,6 +749,58 @@ sub html_initialize {
     $Str .= "<pre>";
     $r->print($Str);
     $r->rflush();
+
+    $r->print(<<JS);
+<script type="text/javascript">
+// get the left offset of a given widget as an absolute position
+function getLeftOffset (element) {
+    return collect(element, "offsetLeft");
+}
+
+// get the top offset of a given widget as an absolute position
+function getTopOffset (element) {
+    return collect(element, "offsetTop");
+}
+
+function collect(element, att) {
+    var val = 0;
+    while(element) {
+        val += element[att];
+        element = element.offsetParent;
+    }
+    return val;
+}
+
+var currentDiv;
+var currentElement;
+function popup_score(element, score) {
+    popdown_score();
+    var left = getLeftOffset(element);
+    var top = getTopOffset(element);
+    var div = document.createElement("div");
+    div.className = "LC_chrt_popup";
+    div.appendChild(document.createTextNode(score));
+    div.style.position = "absolute";
+    div.style.top = (top - 25) + "px";
+    div.style.left = (left - 10) + "px";
+    currentDiv = div;
+    document.body.insertBefore(div, document.body.childNodes[0]);
+    element.className = "LC_chrt_popup_up";
+    currentElement = element;
+}
+
+function popdown_score() {
+    if (currentDiv) {
+        document.body.removeChild(currentDiv);
+    }
+    if (currentElement) {
+        currentElement.className = 'LC_chrt_popup_exists';
+    }
+    currentDiv = undefined;
+}
+</script>
+JS
+
     #
     # Let the user know what we are doing
     my $studentcount = scalar(@Apache::lonstatistics::Students); 
@@ -762,12 +844,17 @@ sub html_outputstudent {
     my @tmp = &Apache::loncoursedata::get_current_state
         ($student->{'username'},$student->{'domain'},undef,
          $env{'request.course.id'});
-    if ((scalar @tmp > 0) && ($tmp[0] !~ /^error:/)) {
+    if ((scalar @tmp > 0) && ($tmp[0] !~ /^error:(.*)/)) {
         %StudentsData = @tmp;
-    }
-    if (scalar(@tmp) < 1) {
+    } else {
+	my $error = $1;
+	if (scalar(@tmp) < 1) {
+	    $Str .= '<font color="blue">No Course Data</font>'."\n";
+	} else {
+	    $Str .= '<span class="LC_error">Error getting student data ('.
+		$error.') </span>'."\n";
+	}
         $nodata_count++;
-        $Str .= '<font color="blue">No Course Data</font>'."\n";
         $r->print($Str);
         $r->rflush();
         return;
@@ -1374,7 +1461,7 @@ sub excel_outputstudent {
     foreach my $field (@to_show) {
         my $value = $student->{$field};
         if ($field eq 'comments') {
-            $value = &Apache::lonmsg::retrieve_instructor_comments
+            $value = &Apache::lonmsgdisplay::retrieve_instructor_comments
                 ($student->{'username'},$student->{'domain'});
         }
         $excel_sheet->write($rows_output,$cols_output++,$value);
@@ -1656,7 +1743,7 @@ sub csv_outputstudent {
     foreach my $field (@to_show) {
         my $value = $student->{$field};
         if ($field eq 'comments') {
-            $value = &Apache::lonmsg::retrieve_instructor_comments
+            $value = &Apache::lonmsgdisplay::retrieve_instructor_comments
                 ($student->{'username'},$student->{'domain'});
         }        
         $Str .= '"'.&Apache::loncommon::csv_translate($value).'",';
@@ -1739,7 +1826,7 @@ sub csv_finish {
     #
     # Tell the user where to get their csv file
     $r->print('<br />'.
-              '<a href="'.$filename.'">'.&mt('Your csv file.').'</a>'."\n");
+              '<a href="'.$filename.'">'.&mt('Your CSV file.').'</a>'."\n");
     $r->rflush();
     &csv_cleanup();
     return;
@@ -1748,6 +1835,18 @@ sub csv_finish {
 
 }
 
+# This function will return an HTML string including a star, with
+# a mouseover popup showing the "real" value. An optional second
+# argument lets you show something other than a star.
+sub show_star {
+    my $popup = shift;
+    my $symbol = shift || '*';
+    # Escape the popup for JS.
+    $popup =~ s/([^-a-zA-Z0-9:;,._ ()|!\/?=&*])/'\\' . sprintf("%lo", ord($1))/ge;
+    
+    return "<span class=\"LC_chrt_popup_exists\" onmouseover='popup_score(this, \"$popup\");return false;' onmouseout='popdown_score();return false;'>$symbol</span>";
+}
+
 #######################################################
 #######################################################
 
@@ -1813,12 +1912,12 @@ sub student_tries_on_sequence {
                 if ($status eq 'excused') {
                     $symbol = 'x';
                     $max--;
-                } elsif ($status eq 'correct_by_override') {
+                } elsif ($status eq 'correct_by_override' && !$resource->is_task()) {
                     $symbol = '+';
                     $sum++;
                 } elsif ($tries > 0) {
                     if ($tries > 9) {
-                        $symbol = '*';
+                        $symbol = show_star($tries);
                     } else {
                         $symbol = $tries;
                     }
@@ -1858,14 +1957,12 @@ sub student_tries_on_sequence {
             #
             if ( ($links eq 'yes' && $symbol ne ' ') ||
                  ($links eq 'all')) {
-                if (length($symbol) > 1) {
-                    &Apache::lonnet::logthis('length of symbol "'.$symbol.'" > 1');
-                }
-                $symbol = '<a href="/adm/grades'.
-                    '?symb='.&Apache::lonnet::escape($resource->symb).
+                my $link = '/adm/grades'.
+                    '?symb='.&escape($resource->shown_symb).
                         '&student='.$student->{'username'}.
                             '&userdom='.$student->{'domain'}.
-                                '&command=submission">'.$symbol.'</a>';
+                                '&command=submission';
+                $symbol = &link($symbol, $link);
             }
             $value .= $symbol;
         }
@@ -1880,6 +1977,37 @@ sub student_tries_on_sequence {
     return ($Str,$performance_length,$sum,$max,\@TriesData);
 }
 
+=pod
+
+=item &link
+
+Inputs:
+
+=over 4
+
+=item $text
+
+=item $target
+
+=back
+
+Takes the text and creates a link to the $text that honors
+the value of 'new window' if clicked on, but uses a real 
+'href' so middle and right clicks still work.
+
+$target and $text are assumed to be already correctly escaped; i.e., it
+can be dumped out directly into the output stream as-is.
+
+=cut
+
+sub link {
+    my ($text,$target) = @_;
+    return 
+        "<a href='$target' onclick=\"t=this.href;if(new_window)"
+        ."{window.open(t)}else{return void(window."
+        ."location=t)};return false;\">$text</a>";
+}
+
 #######################################################
 #######################################################
 
@@ -1943,7 +2071,7 @@ sub student_performance_on_sequence {
                 $hasdata = 1;
             }
             #
-            $partscore = Apache::grades::compute_points($weight,$awarded);
+            $partscore = &Apache::grades::compute_points($weight,$awarded);
             if (! defined($awarded)) {
                 $partscore = undef;
             }
@@ -1953,7 +2081,7 @@ sub student_performance_on_sequence {
                 $symbol = sprintf("%.0f",$symbol);
             }
             if (length($symbol) > 1) {
-                $symbol = '*';
+                $symbol = show_star($symbol);
             }
             if (exists($resource_data->{'resource.'.$part.'.solved'}) &&
                 $resource_data->{'resource.'.$part.'.solved'} ne '') {
@@ -1984,11 +2112,12 @@ sub student_performance_on_sequence {
             push (@ScoreData,$partscore);
             #
             if ( ($links eq 'yes' && $symbol ne ' ') || ($links eq 'all')) {
-                $symbol = '<a href="/adm/grades'.
-                    '?symb='.&Apache::lonnet::escape($symb).
+                my $link = '/adm/grades' .
+                    '?symb='.&escape($resource->shown_symb).
                     '&student='.$student->{'username'}.
                     '&userdom='.$student->{'domain'}.
-                    '&command=submission">'.$symbol.'</a>';
+                    '&command=submission';
+                $symbol = &link($symbol, $link);
             }
             $Str .= $symbol;
         }