1: # The LearningOnline Network with CAPA
2: # (Publication Handler
3: #
4: # $Id: lonstudentassessment.pm,v 1.28 2003/02/21 18:41:56 matthew Exp $
5: #
6: # Copyright Michigan State University Board of Trustees
7: #
8: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
9: # LON-CAPA is free software; you can redistribute it and/or modify
10: # it under the terms of the GNU General Public License as published by
11: # the Free Software Foundation; either version 2 of the License, or
12: # (at your option) any later version.
13: #
14: # LON-CAPA is distributed in the hope that it will be useful,
15: # but WITHOUT ANY WARRANTY; without even the implied warranty of
16: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17: # GNU General Public License for more details.
18: #
19: # You should have received a copy of the GNU General Public License
20: # along with LON-CAPA; if not, write to the Free Software
21: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22: #
23: # /home/httpd/html/adm/gpl.txt
24: #
25: # http://www.lon-capa.org/
26: #
27: # (Navigate problems for statistical reports
28: #
29: #######################################################
30: #######################################################
31:
32: =pod
33:
34: =head1 NAME
35:
36: lonstudentassessment
37:
38: =head1 SYNOPSIS
39:
40: Presents assessment data about a student or a group of students.
41:
42: =head1 Subroutines
43:
44: =over 4
45:
46: =cut
47:
48: #######################################################
49: #######################################################
50:
51: package Apache::lonstudentassessment;
52:
53: use strict;
54: use Apache::lonstatistics;
55: use Apache::lonhtmlcommon;
56: use Apache::loncoursedata;
57: use Apache::lonnet; # for logging porpoises
58: use GDBM_File;
59:
60: #######################################################
61: #######################################################
62:
63: =pod
64:
65: =item &BuildStudentAssessmentPage()
66:
67: Inputs:
68:
69: =over 4
70:
71: =item $cacheDB The name of the cache file used to store student data
72:
73: =item $students Array ref containing the name(s) of the students
74: selected for display
75:
76: =item $courseID The ID of the course
77:
78: =item $formName The name of the html form - 'Statistics'
79:
80: =item $headings Array ref of headings to show
81:
82: =item $spacing A string of spaces
83:
84: =item $studentInformation Array ref of possible headings for student info
85: ('fullname','section',...)
86:
87: =item $r Apache Request
88:
89: =item $c Apache Connection
90:
91: =back
92:
93: =cut
94:
95: #######################################################
96: #######################################################
97: sub BuildStudentAssessmentPage {
98: my ($cacheDB,$students,$courseID,$formName,$headings,$spacing,
99: $studentInformation,$r,$c)=@_;
100: my %cache;
101: unless(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER(),0640)) {
102: $r->print('<html><body>Unable to tie database.</body></html>');
103: return;
104: }
105:
106: # Remove students who don't have the proper section.
107: my @sectionsSelected = split(':',$cache{'sectionsSelected'});
108: for(my $studentIndex=((scalar @$students)-1); $studentIndex>=0;
109: $studentIndex--) {
110: my $value = $cache{$students->[$studentIndex].':section'};
111: my $found = 0;
112: foreach (@sectionsSelected) {
113: if($_ eq 'none') {
114: if($value eq '' || !defined($value) || $value eq ' ') {
115: $found = 1;
116: last;
117: }
118: } else {
119: if($value eq $_) {
120: $found = 1;
121: last;
122: }
123: }
124: }
125: if($found == 0) {
126: splice(@$students, $studentIndex, 1);
127: }
128: }
129: my ($infoHeadings, $infoKeys, $sequenceHeadings, $sequenceKeys,
130: $doNotShow) =
131: &ShouldShowColumns(\%cache, $headings, $studentInformation);
132:
133: my $selectedName = &FindSelectedStudent(\%cache,
134: $cache{'StudentAssessmentStudent'},
135: $students);
136: $r->print(&CreateInterface(\%cache, $selectedName, $students, $formName,
137: $doNotShow));
138: $r->rflush();
139:
140: my $Str = '';
141: if($selectedName eq 'No Student Selected') {
142: $Str .= '<h3><font color=blue>WARNING: ';
143: $Str .= 'Please select a student</font></h3>';
144: $r->print($Str);
145: return;
146: }
147:
148: $r->print(&CreateTableHeadings(\%cache, $spacing, $infoKeys, $infoHeadings,
149: $sequenceKeys, $sequenceHeadings));
150: untie(%cache);
151: if($c->aborted()) { return $Str; }
152:
153: my $selected=0;
154: my $Count = 0;
155: $r->print('<pre>'."\n");
156: foreach (@$students) {
157: if($c->aborted()) { return $Str; }
158: next if ($_ ne $selectedName &&
159: $selectedName ne 'All Students');
160: $selected = 1;
161:
162: my @who = ($_);
163: next if(&Apache::loncoursedata::DownloadStudentCourseData(\@who, 'true',
164: $cacheDB, 'true',
165: 'false', $courseID,
166: $r, $c) ne 'OK');
167: next if($c->aborted());
168:
169: if(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER(),0640)) {
170: my @before=();
171: my @after=();
172: my @updateColumn=();
173: my $foundUpdate = 0;
174: foreach(@$infoKeys) {
175: if(/updateTime/) {
176: $foundUpdate=1;
177: push(@updateColumn, $_);
178: next;
179: }
180: if($foundUpdate) {
181: push(@after, $_);
182: } else {
183: push(@before, $_);
184: }
185: }
186: $Count++;
187: my $out = '';
188: $out .= sprintf("%3d) ", $Count);
189: if($Count % 2) {
190: $out .= '<bgcolor="#FFFFFF">';
191: } else {
192: $out .= '<bgcolor="#505050">';
193: }
194: my $displayString = $out.'DISPLAYDATA'.$spacing;
195: $r->print(&Apache::lonhtmlcommon::FormatStudentInformation(
196: \%cache, $_,
197: \@before,
198: $displayString,
199: 'preformatted'));
200:
201: if($foundUpdate) {
202: $displayString = '';
203: $displayString .= '<a href="/adm/statistics?reportSelected=';
204: $displayString .= &Apache::lonnet::escape('Student Assessment');
205: $displayString .= '&download='.$_.'">';
206: $displayString .= 'DISPLAYDATA</a>'.$spacing;
207: $r->print(&Apache::lonhtmlcommon::FormatStudentInformation(
208: \%cache, $_,
209: \@updateColumn,
210: $displayString,
211: 'preformatted'));
212: }
213:
214: $displayString = 'DISPLAYDATA'.$spacing;
215: $r->print(&Apache::lonhtmlcommon::FormatStudentInformation(
216: \%cache, $_,
217: \@after,
218: $displayString,
219: 'preformatted'));
220: $r->print(&StudentReport(\%cache, $_, $spacing, $sequenceKeys));
221: $r->print("\n");
222: $r->rflush();
223: untie(%cache);
224: }
225: }
226: $r->print('</pre>'."\n");
227: if($selected == 0) {
228: $Str .= '<h3><font color=blue>WARNING: ';
229: $Str .= 'No Students enrolled OR Please select a student</font></h3>';
230: $r->print($Str);
231: } else {
232: if(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER(),0640)) {
233: $r->print(&StudentAverageTotal(\%cache, $students, $sequenceKeys));
234: untie(%cache);
235: }
236: }
237: return;
238: }
239: #######################################################
240: #######################################################
241:
242: =pod
243:
244: =item &CreateInterface()
245:
246: Called by &BuildStudentAssessmentPage to create the top part of the
247: page which displays the chart.
248:
249: Inputs:
250:
251: =over 4
252:
253: =item $cache The ubiquitous cache
254:
255: =item $selectedName The name of the currently selected student, or
256: 'All Students' or 'No Student Selected'.
257:
258: =item $students Array ref containing the name(s) of the students selected
259: for display.
260:
261: =item $formName The name of the HTML form to use, 'Statistics'
262:
263: =item $doNotShow Array ref containing the names of columns to not show
264:
265: =back
266:
267: Returns: A string containing the HTML for the headers and top table for
268: the chart page.
269:
270: =cut
271:
272: #######################################################
273: #######################################################
274: sub CreateInterface {
275: my($cache,$selectedName,$students,$formName,$doNotShow)=@_;
276:
277: my $Str = '';
278: $Str .= &CreateLegend();
279: $Str .= '<table><tr><td>'."\n";
280: $Str .= '<input type="submit" name="PreviousStudent" ';
281: $Str .= 'value="Previous Student" />'."\n";
282: $Str .= '   '."\n";
283: $Str .= &Apache::lonhtmlcommon::StudentOptions($cache, $students,
284: $selectedName,
285: 'StudentAssessment',
286: $formName);
287: $Str .= "\n".'   '."\n";
288: $Str .= '<input type="submit" name="NextStudent" ';
289: $Str .= 'value="Next Student" />'."\n";
290: $Str .= '</td></tr></table>'."\n";
291: $Str .= '<table cellspacing="5"><tr>'."\n";
292: $Str .= '<td align="center"><b>Select Sections</b>'."\n";
293: $Str .= '</td>'."\n";
294: $Str .= '<td align="center"><b>Select column to view:</b></td>'."\n";
295: $Str .= '<td></td></tr>'."\n";
296:
297: $Str .= '<tr><td align="center">'."\n";
298: my @sections = split(':',$cache->{'sectionList'});
299: my @selectedSections = split(':',$cache->{'sectionsSelected'});
300: $Str .= &Apache::lonhtmlcommon::MultipleSectionSelect(\@sections,
301: \@selectedSections,
302: 'Statistics');
303: $Str .= '</td><td align="center">';
304: $Str .= &CreateColumnSelectionBox($doNotShow);
305: $Str .= '</td><td>'."\n";
306: $Str .= '<input type="submit" name="DefaultColumns" ';
307: $Str .= 'value="Default Column Display" />'."\n";
308: $Str .= '</td><td>'."\n";
309: $Str .= '<input type="submit" name="displaymode" ';
310: if (! exists($ENV{'form.displaymode'}) ||
311: lc($ENV{'form.displaymode'}) eq 'display with links') {
312: $Str .= 'value="Display without links" />';
313: # Set the current value, in case it is undefined
314: $ENV{'form.displaymode'} = 'Display with links';
315: } else {
316: $Str .= 'value="Display with links" />';
317: }
318: $Str .= "\n";
319: $Str .= '</td></tr></table>'."\n";
320:
321: return $Str;
322: }
323: #######################################################
324: #######################################################
325:
326: =pod
327:
328: =item &CreateTableHeadings()
329:
330: Create HTML for the columns of student data to show.
331: Called by &BuildStudentAssessmentPage(). Calls
332: &Apache::lonhtmlcommon::CreateHeadings().
333:
334: Inputs:
335:
336: =over 4
337:
338: =item $cache The ubiquitous cache
339:
340: =item $spacing A string of spaces
341:
342: =item $infoKeys Array ref to names of keys to display from the cache
343: which describe students
344:
345: =item $infoHeadings Array ref to headings of columns for student info
346:
347: =item $sequenceKeys Array ref of names of keys to use to retrieve sequence
348: data from the cache
349:
350: =item $sequenceHeadings Array ref of names of sequences used for output.
351:
352: =back
353:
354: Returns: A string containing the HTML of the table headings.
355:
356: =cut
357:
358: #######################################################
359: #######################################################
360: sub CreateTableHeadings {
361: my($cache,$spacing,$infoKeys,$infoHeadings,$sequenceKeys,
362: $sequenceHeadings)=@_;
363:
364: # my $Str = '     ';
365: my $Str = '';
366: $Str .= '<table border="0" cellpadding="0" cellspacing="0">'."\n";
367: $Str .= '<tr>'."\n";
368: $Str .= '<td><pre> </pre></td>'."\n";
369: $Str .= &CreateColumnSelectors($infoHeadings, $sequenceHeadings,
370: $sequenceKeys);
371: $Str .= '<td></td></tr>'."\n";
372:
373: $Str .= '<tr>'."\n";
374: my $displayString = '';
375: $displayString .= '<td><pre> </pre></td>'."\n";
376: $displayString .= '<td align="left"><pre><a href="/adm/statistics?';
377: $displayString .= 'sort=LINKDATA">DISPLAYDATA</a>FORMATTING';
378: $displayString .= $spacing.'</pre></td>'."\n";
379: $Str .= &Apache::lonhtmlcommon::CreateHeadings($cache,
380: $infoKeys,
381: $infoHeadings,
382: $displayString,
383: 'preformatted');
384:
385: $displayString = '<td align="left"><pre>DISPLAYDATAFORMATTING'.$spacing;
386: $displayString .= '</pre></td>'."\n";
387: $Str .= &Apache::lonhtmlcommon::CreateHeadings($cache,
388: $sequenceKeys,
389: $sequenceHeadings,
390: $displayString,
391: 'preformatted');
392:
393: $Str .= '<td><pre>Total Solved/Total Problems</pre></td>';
394: $Str .= '</tr></table>'."\n";
395:
396: return $Str;
397: }
398:
399: #######################################################
400: #######################################################
401:
402: =pod
403:
404: =item &StudentReport()
405:
406: This is the workhorse subroutine - it handles formatting and display of a
407: students performance data. It processes one row of the chart.
408:
409: Input:
410:
411: =over 4
412:
413: =item $cache The ubiquitous cache
414:
415: =item $name The name and domain of the current student in name:domain format
416:
417: =item $spacing A string containing spaces.
418:
419: =item $showSequences Array ref containing the sequences to display
420:
421: =back
422:
423: Output: $Str
424:
425: $Str: Formatted string that is an entire row of the chart. It is a
426: concatenation of student information and student course information.
427:
428: =cut
429:
430: #######################################################
431: #######################################################
432: sub StudentReport {
433: my ($cache,$name,$spacing,$showSequences)=@_;
434: my ($username,$domain)=split(':',$name);
435:
436: my $Str = '';
437: if(defined($cache->{$name.':error'})) {
438: return $Str;
439: }
440: if($cache->{$name.':error'} =~ /course/) {
441: $Str .= '<b><font color="blue">No course data for student </font>';
442: $Str .= '<font color="red">'.$username.'.</font></b><br>';
443: return $Str;
444: }
445:
446: my $hasVersion = 'false';
447: my $hasFinalData = 'false';
448: foreach my $sequence (@$showSequences) {
449: my $hasData = 'false';
450: my $characterCount=0;
451: foreach my $problemID (split(':', $cache->{$sequence.':problems'})) {
452: my $problem = $cache->{$problemID.':problem'};
453: # All grades (except for versionless parts) are displayed as links
454: # to their submission record. Loop through all the parts for the
455: # current problem in the correct order and prepare the output links
456: foreach(split(/\:/,$cache->{$sequence.':'.$problemID.
457: ':parts'})) {
458: if($cache->{$name.':'.$problemID.':NoVersion'} eq 'true' ||
459: $cache->{$name.':'.$problemID.':'.$_.':code'} eq ' ' ||
460: $cache->{$name.':'.$problemID.':'.$_.':code'} eq '') {
461: $Str .= ' ';
462: $characterCount++;
463: next;
464: }
465: $hasVersion = 'true';
466: $hasData = 'true';
467: if (lc($ENV{'form.displaymode'}) ne 'display without links') {
468: $Str .= '<a href="/adm/grades?symb=';
469: $Str .= &Apache::lonnet::escape($problem);
470: $Str .= '&student='.$username.'&domain='.$domain;
471: $Str .= '&command=submission">';
472: }
473: my $code = $cache->{$name.':'.$problemID.':'.$_.':code'};
474: my $tries = $cache->{$name.':'.$problemID.':'.$_.':tries'};
475: if($code eq '*' && $tries < 10 && $tries ne '') {
476: $code = $tries;
477: }
478: $Str .= $code;
479: if (lc($ENV{'form.displaymode'}) ne 'display without links') {
480: $Str .= '</a>';
481: }
482: $characterCount++;
483: }
484: }
485:
486: # Output the number of correct answers for the current sequence.
487: # This part takes up 6 character slots, but is formated right
488: # justified.
489: my $spacesNeeded=$cache->{$sequence.':columnWidth'}-$characterCount;
490: $spacesNeeded -= 3;
491: $Str .= (' 'x$spacesNeeded);
492:
493: # my $outputProblemsCorrect = sprintf("%3d", $cache->{$name.':'.$sequence.
494: # ':problemsCorrect'});
495:
496: my $outputProblemsCorrect = sprintf("%2d/%2d", $cache->{$name.':'.$sequence.
497: ':problemsCorrect'},
498: $characterCount);
499: if($hasData eq 'true') {
500: $Str .= '<font color="#007700">'.$outputProblemsCorrect.'</font>';
501: $hasFinalData = 'true';
502: } else {
503: $Str .= '<font color="#007700"> </font>';
504: }
505: $Str .= $spacing;
506: }
507:
508: # Output the total correct problems over the total number of problems.
509: # I don't like this type of formatting, but it is a solution. Need
510: # a way to dynamically determine the space requirements.
511: my $outputProblemsSolved = sprintf("%4d", $cache->{$name.':problemsSolved'});
512: my $outputTotalProblems = sprintf("%4d", $cache->{$name.':totalProblems'});
513: if($hasFinalData eq 'true') {
514: $Str .= '<font color="#000088">'.$outputProblemsSolved.
515: ' / '.$outputTotalProblems.'</font>';
516: } else {
517: $Str .= '<font color="#000088"> </font>';
518: }
519:
520: if($hasVersion eq 'false') {
521: $Str = '<b><font color="blue">No course data.</font></b>';
522: }
523:
524: return $Str;
525: }
526:
527: #######################################################
528: #######################################################
529:
530: #######################################################
531: #######################################################
532: sub StudentAverageTotal {
533: my ($cache, $students, $sequenceKeys)=@_;
534: my $Str = "\n<b>Summary Tables:</b>\n";
535: my %Correct = ();
536: my $ProblemsSolved = 0;
537: my $TotalProblems = 0;
538: my $StudentCount = 0;
539:
540: foreach my $name (@$students) {
541: $StudentCount++;
542: foreach my $sequence (@$sequenceKeys) {
543: $Correct{$sequence} +=
544: $cache->{$name.':'.$sequence.':problemsCorrect'};
545: }
546: $ProblemsSolved += $cache->{$name.':problemsSolved'};
547: $TotalProblems += $cache->{$name.':totalProblems'};
548: }
549: if ($StudentCount) {
550: $ProblemsSolved = sprintf( "%.2f",
551: $ProblemsSolved/$StudentCount);
552: $TotalProblems /= $StudentCount;
553: } else {
554: $ProblemsSolved = 0;
555: $TotalProblems = 0;
556: }
557:
558: $Str .= '<table border=2 cellspacing="1">'."\n";
559: $Str .= '<tr><td><b>Students Count</b></td><td><b>'.
560: $StudentCount.'</b></td></tr>'."\n";
561: $Str .= '<tr><td><b>Total Problems</b></td><td><b>'.
562: $TotalProblems.'</b></td></tr>'."\n";
563: $Str .= '<tr><td><b>Average Correct</b></td><td><b>'.
564: $ProblemsSolved.'</b></td></tr>'."\n";
565: $Str .= '</table>'."\n";
566:
567: $Str .= '<table border=2 cellspacing="1">'."\n";
568: $Str .= '<tr><th>Title</th><th>Total Problems</th>'.
569: '<th>Average Correct</th></tr>'."\n";
570: foreach my $S(@$sequenceKeys) {
571: my $title=$cache->{$S.':title'};
572: #$Str .= $cache->{$S.':problems'};
573: #my @problems=split(':', $cache->{$S.':problems'});
574: #my $pCount=scalar @problems;
575: my $pCount=MaxSeqPr($cache,@$students[0],$S);
576: my $crr;
577: if ($StudentCount) {
578: $crr=sprintf( "%.2f", $Correct{$S}/$StudentCount );
579: } else {
580: $crr="0.00";
581: }
582: $Str .= '<tr><td>'.$title.
583: '</td><td align=center>'.$pCount.
584: '</td><td align=center>'.$crr.
585: '</td></tr>'."\n";
586: }
587:
588: $Str .= '</table>'."\n";
589:
590: return $Str;
591: }
592:
593: #######################################################
594: #######################################################
595:
596: #######################################################
597: #######################################################
598: sub MaxSeqPr {
599: my ($cache, $name, $sequence)=@_;
600: my $prCount=0;
601: foreach my $problemID (split(':', $cache->{$sequence.':problems'})) {
602: my $problem = $cache->{$problemID.':problem'};
603: foreach(split(/\:/,$cache->{$sequence.':'.$problemID.':parts'})) {
604: if($cache->{$name.':'.$problemID.':NoVersion'} eq 'true' ||
605: $cache->{$name.':'.$problemID.':'.$_.':code'} eq ' ' ||
606: $cache->{$name.':'.$problemID.':'.$_.':code'} eq '') {
607: $prCount++;
608: next;
609: }
610: $prCount++;
611: }
612: }
613: return $prCount;
614: }
615:
616: #######################################################
617: #######################################################
618:
619: =pod
620:
621: =item &CreateLegend()
622:
623: This function returns a formatted string containing the legend for the
624: chart. The legend describes the symbols used to represent grades for
625: problems.
626:
627: =cut
628:
629: #######################################################
630: #######################################################
631: sub CreateLegend {
632: my $Str = "<p><pre>".
633: " 1 correct by student in 1 try\n".
634: " 7 correct by student in 7 tries\n".
635: " * correct by student in more than 9 tries\n".
636: " + correct by hand grading or override\n".
637: " - incorrect by override\n".
638: " . incorrect attempted\n".
639: " # ungraded attempted\n".
640: " not attempted (blank field)\n".
641: " x excused".
642: "</pre><p>";
643: return $Str;
644: }
645:
646: #######################################################
647: #######################################################
648:
649: =pod
650:
651: =item &CreateColumnSelectionBox()
652:
653: If there are columns not being displayed then this selection box is created
654: with a list of those columns. When selections are made and the page
655: refreshed, the columns will be removed from this box and the column is
656: put back in the chart. If there is no columns to select, no row is added
657: to the interface table.
658:
659: =over 4
660: Input: $CacheData, $headings
661:
662: $CacheData: A pointer to a hash tied to the cached data
663:
664: $headings: An array of the names of the columns for the student information.
665: They are used for displaying which columns are missing.
666:
667: Output: $notThere
668:
669: $notThere: The string contains one row of a table. The first column has the
670: name of the selection box. The second contains the selection box
671: which has a size of four.
672:
673: =back
674:
675: =cut
676:
677: #######################################################
678: #######################################################
679: sub CreateColumnSelectionBox {
680: my ($doNotShow)=@_;
681:
682: my $notThere = '';
683: $notThere .= '<select name="ReselectColumns" size="4" ';
684: $notThere .= 'multiple="true">'."\n";
685:
686: for(my $index=0; $index<$doNotShow->{'count'}; $index++) {
687: my $name = $doNotShow->{$index.':name'};
688: $notThere .= '<option value="';
689: $notThere .= $doNotShow->{$index.':id'}.'">';
690: $notThere .= $name.'</option>'."\n";
691: }
692:
693: $notThere .= '</select>';
694:
695: return $notThere;
696: }
697:
698: #######################################################
699: #######################################################
700:
701: =pod
702:
703: =item &CreateColumnSelectors()
704:
705: This function generates the checkboxes above the column headings. The
706: column will be removed if the checkbox is unchecked.
707:
708: =over 4
709:
710: Input: $CacheData, $headings
711:
712: $CacheData: A pointer to a hash tied to the cached data
713:
714: $headings: An array of the names of the columns for the student
715: information. They are used to know what are the student information columns
716:
717: Output: $present
718:
719: $present: The string contains the first row of a table. Each column contains
720: a checkbox which is left justified. Currently left justification is used
721: for consistency of location over the column in which it presides.
722:
723: =back
724:
725: =cut
726:
727: #######################################################
728: #######################################################
729: sub CreateColumnSelectors {
730: my ($infoHeadings, $sequenceHeadings, $sequenceKeys)=@_;
731:
732: my $present = '';
733: for(my $index=0; $index<(scalar @$infoHeadings); $index++) {
734: $present .= '<td align="left">';
735: $present .= '<input type="checkbox" checked="on" ';
736: $present .= 'name="HeadingColumn'.$infoHeadings->[$index].'" />';
737: $present .= '</td>'."\n";
738: }
739:
740: for(my $index=0; $index<(scalar @$sequenceHeadings); $index++) {
741: $present .= '<td align="left">';
742: $present .= '<input type="checkbox" checked="on" ';
743: $present .= 'name="SequenceColumn'.$sequenceKeys->[$index].'" />';
744: $present .= '</td>'."\n";
745: }
746:
747: return $present;
748: }
749:
750: #######################################################
751: #######################################################
752:
753: =pod
754:
755: =back
756:
757: =head1 HELPER FUNCTIONS
758:
759: =over 4
760:
761: =cut
762:
763: #######################################################
764: #######################################################
765: sub FindSelectedStudent {
766: my($cache, $selectedName, $students)=@_;
767:
768: if($selectedName eq 'All Students' ||
769: $selectedName eq 'No Student Selected') {
770: return $selectedName;
771: }
772:
773: for(my $index=0; $index<(scalar @$students); $index++) {
774: my $fullname = $cache->{$students->[$index].':fullname'};
775: if($fullname eq $selectedName) {
776: if($cache->{'StudentAssessmentMove'} eq 'next') {
777: if($index == ((scalar @$students) - 1)) {
778: $selectedName = $students->[0];
779: return $selectedName;
780: } else {
781: $selectedName = $students->[$index+1];
782: return $selectedName;
783: }
784: } elsif($cache->{'StudentAssessmentMove'} eq 'previous') {
785: if($index == 0) {
786: $selectedName = $students->[-1];
787: return $selectedName;
788: } else {
789: $selectedName = $students->[$index-1];
790: return $selectedName;
791: }
792: } else {
793: $selectedName = $students->[$index];
794: return $selectedName;
795: }
796: last;
797: }
798: }
799:
800: return 'No Student Selected';
801: }
802: #######################################################
803: #######################################################
804:
805: =pod
806:
807: =item &ShouldShowColumn()
808:
809: Determine if a specified column should be shown on the chart.
810:
811: =over 4
812:
813: Input: $cache, $test
814:
815: $cache: A pointer to the hash tied to the cached data
816:
817: $test: The form name of the column (heading.$headingIndex) or
818: (sequence.$sequenceIndex)
819:
820: =back
821:
822: =cut
823:
824: #######################################################
825: #######################################################
826: sub ShouldShowColumns {
827: my ($cache,$headings,$cacheKey)=@_;
828:
829: my @infoKeys=();
830: my @infoHeadings=();
831:
832: my @sequenceKeys=();
833: my @sequenceHeadings=();
834:
835: my %doNotShow;
836:
837: my $index;
838: my $count = 0;
839: my $check = '';
840: for($index=0; $index < scalar @$headings; $index++) {
841: $check = 'HeadingColumn'.$headings->[$index];
842: if($cache->{'HeadingsFound'} =~ /$check/) {
843: push(@infoHeadings, $headings->[$index]);
844: push(@infoKeys, $cacheKey->[$index]);
845: } else {
846: $doNotShow{$count.':name'} = $headings->[$index];
847: $doNotShow{$count.':id'} = 'HeadingColumn'.$headings->[$index];
848: $count++;
849: }
850: }
851:
852: foreach my $sequence (split(/\:/,$cache->{'orderedSequences'})) {
853: $check = 'SequenceColumn'.$sequence;
854: if($cache->{'SequencesFound'} eq 'All Sequences' ||
855: $cache->{'SequencesFound'} =~ /$check/) {
856: push(@sequenceHeadings, $cache->{$sequence.':title'});
857: push(@sequenceKeys, $sequence);
858: } else {
859: $doNotShow{$count.':name'} = $cache->{$sequence.':title'};
860: $doNotShow{$count.':id'} = 'SequenceColumn'.$sequence;
861: $count++;
862: }
863: }
864:
865: $doNotShow{'count'} = $count;
866:
867: return (\@infoHeadings, \@infoKeys, \@sequenceHeadings,
868: \@sequenceKeys, \%doNotShow);
869: }
870: 1;
871:
872: #######################################################
873: #######################################################
874:
875: =pod
876:
877: =back
878:
879: =cut
880:
881: #######################################################
882: #######################################################
883:
884: __END__
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>