Annotation of loncom/interface/loncommon.pm, revision 1.208

1.10      albertel    1: # The LearningOnline Network with CAPA
1.1       albertel    2: # a pile of common routines
1.10      albertel    3: #
1.208   ! matthew     4: # $Id: loncommon.pm,v 1.207 2004/08/25 18:13:00 matthew Exp $
1.10      albertel    5: #
                      6: # Copyright Michigan State University Board of Trustees
                      7: #
                      8: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
                      9: #
                     10: # LON-CAPA is free software; you can redistribute it and/or modify
                     11: # it under the terms of the GNU General Public License as published by
                     12: # the Free Software Foundation; either version 2 of the License, or
                     13: # (at your option) any later version.
                     14: #
                     15: # LON-CAPA is distributed in the hope that it will be useful,
                     16: # but WITHOUT ANY WARRANTY; without even the implied warranty of
                     17: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     18: # GNU General Public License for more details.
                     19: #
                     20: # You should have received a copy of the GNU General Public License
                     21: # along with LON-CAPA; if not, write to the Free Software
                     22: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
                     23: #
                     24: # /home/httpd/html/adm/gpl.txt
                     25: #
                     26: # http://www.lon-capa.org/
                     27: #
1.1       albertel   28: 
                     29: # Makes a table out of the previous attempts
1.2       albertel   30: # Inputs result_from_symbread, user, domain, course_id
1.16      harris41   31: # Reads in non-network-related .tab files
1.1       albertel   32: 
1.35      matthew    33: # POD header:
                     34: 
1.45      matthew    35: =pod
                     36: 
1.35      matthew    37: =head1 NAME
                     38: 
                     39: Apache::loncommon - pile of common routines
                     40: 
                     41: =head1 SYNOPSIS
                     42: 
1.112     bowersj2   43: Common routines for manipulating connections, student answers,
                     44:     domains, common Javascript fragments, etc.
1.35      matthew    45: 
1.112     bowersj2   46: =head1 OVERVIEW
1.35      matthew    47: 
1.112     bowersj2   48: A collection of commonly used subroutines that don't have a natural
                     49: home anywhere else. This collection helps remove
1.35      matthew    50: redundancy from other modules and increase efficiency of memory usage.
                     51: 
                     52: =cut 
                     53: 
                     54: # End of POD header
1.1       albertel   55: package Apache::loncommon;
                     56: 
                     57: use strict;
1.22      www        58: use Apache::lonnet();
1.46      matthew    59: use GDBM_File;
1.51      www        60: use POSIX qw(strftime mktime);
1.99      www        61: use Apache::Constants qw(:common :http :methods);
1.1       albertel   62: use Apache::lonmsg();
1.82      www        63: use Apache::lonmenu();
1.117     www        64: use Apache::lonlocal;
1.139     matthew    65: use HTML::Entities;
1.117     www        66: 
1.22      www        67: my $readit;
                     68: 
1.157     matthew    69: ##
                     70: ## Global Variables
                     71: ##
1.46      matthew    72: 
1.20      www        73: # ----------------------------------------------- Filetypes/Languages/Copyright
1.12      harris41   74: my %language;
1.124     www        75: my %supported_language;
1.12      harris41   76: my %cprtag;
1.192     taceyjo1   77: my %scprtag;
1.12      harris41   78: my %fe; my %fd;
1.41      ng         79: my %category_extensions;
1.12      harris41   80: 
1.63      www        81: # ---------------------------------------------- Designs
                     82: 
                     83: my %designhash;
                     84: 
1.46      matthew    85: # ---------------------------------------------- Thesaurus variables
1.144     matthew    86: #
                     87: # %Keywords:
                     88: #      A hash used by &keyword to determine if a word is considered a keyword.
                     89: # $thesaurus_db_file 
                     90: #      Scalar containing the full path to the thesaurus database.
1.46      matthew    91: 
                     92: my %Keywords;
                     93: my $thesaurus_db_file;
                     94: 
1.144     matthew    95: #
                     96: # Initialize values from language.tab, copyright.tab, filetypes.tab,
                     97: # thesaurus.tab, and filecategories.tab.
                     98: #
1.18      www        99: BEGIN {
1.46      matthew   100:     # Variable initialization
                    101:     $thesaurus_db_file = $Apache::lonnet::perlvar{'lonTabDir'}."/thesaurus.db";
                    102:     #
1.22      www       103:     unless ($readit) {
1.12      harris41  104: # ------------------------------------------------------------------- languages
                    105:     {
1.158     raeburn   106:         my $langtabfile = $Apache::lonnet::perlvar{'lonTabDir'}.
                    107:                                    '/language.tab';
                    108:         if ( open(my $fh,"<$langtabfile") ) {
                    109:             while (<$fh>) {
                    110:                 next if /^\#/;
                    111:                 chomp;
                    112:                 my ($key,$two,$country,$three,$enc,$val,$sup)=(split(/\t/,$_));
                    113:                 $language{$key}=$val.' - '.$enc;
                    114:                 if ($sup) {
                    115:                     $supported_language{$key}=$sup;
                    116:                 }
                    117:             }
                    118:             close($fh);
                    119:         }
1.12      harris41  120:     }
                    121: # ------------------------------------------------------------------ copyrights
                    122:     {
1.158     raeburn   123:         my $copyrightfile = $Apache::lonnet::perlvar{'lonIncludes'}.
                    124:                                   '/copyright.tab';
                    125:         if ( open (my $fh,"<$copyrightfile") ) {
                    126:             while (<$fh>) {
                    127:                 next if /^\#/;
                    128:                 chomp;
                    129:                 my ($key,$val)=(split(/\s+/,$_,2));
                    130:                 $cprtag{$key}=$val;
                    131:             }
                    132:             close($fh);
                    133:         }
1.12      harris41  134:     }
1.192     taceyjo1  135: # ------------------------------------------------------------------ source copyrights
                    136:     {
                    137:         my $sourcecopyrightfile = $Apache::lonnet::perlvar{'lonIncludes'}.
                    138:                                   '/source_copyright.tab';
                    139:         if ( open (my $fh,"<$sourcecopyrightfile") ) {
                    140:             while (<$fh>) {
                    141:                 next if /^\#/;
                    142:                 chomp;
                    143:                 my ($key,$val)=(split(/\s+/,$_,2));
                    144:                 $scprtag{$key}=$val;
                    145:             }
                    146:             close($fh);
                    147:         }
                    148:     }
1.63      www       149: 
                    150: # -------------------------------------------------------------- domain designs
                    151: 
                    152:     my $filename;
                    153:     my $designdir=$Apache::lonnet::perlvar{'lonTabDir'}.'/lonDomColors';
                    154:     opendir(DIR,$designdir);
                    155:     while ($filename=readdir(DIR)) {
                    156: 	my ($domain)=($filename=~/^(\w+)\./);
                    157:     {
1.158     raeburn   158:         my $designfile = $designdir.'/'.$filename;
                    159:         if ( open (my $fh,"<$designfile") ) {
                    160:             while (<$fh>) {
                    161:                 next if /^\#/;
                    162:                 chomp;
                    163:                 my ($key,$val)=(split(/\=/,$_));
                    164:                 if ($val) { $designhash{$domain.'.'.$key}=$val; }
                    165:             }
                    166:             close($fh);
                    167:         }
1.63      www       168:     }
                    169: 
                    170:     }
                    171:     closedir(DIR);
                    172: 
                    173: 
1.15      harris41  174: # ------------------------------------------------------------- file categories
                    175:     {
1.158     raeburn   176:         my $categoryfile = $Apache::lonnet::perlvar{'lonTabDir'}.
                    177:                                   '/filecategories.tab';
                    178:         if ( open (my $fh,"<$categoryfile") ) {
                    179:             while (<$fh>) {
                    180:                 next if /^\#/;
                    181:                 chomp;
                    182:                 my ($extension,$category)=(split(/\s+/,$_,2));
                    183:                 push @{$category_extensions{lc($category)}},$extension;
                    184:             }
                    185:             close($fh);
                    186:         }
                    187: 
1.15      harris41  188:     }
1.12      harris41  189: # ------------------------------------------------------------------ file types
                    190:     {
1.158     raeburn   191:         my $typesfile = $Apache::lonnet::perlvar{'lonTabDir'}.
                    192:                '/filetypes.tab';
                    193:         if ( open (my $fh,"<$typesfile") ) {
1.16      harris41  194:             while (<$fh>) {
1.158     raeburn   195:                 next if (/^\#/);
                    196:                 chomp;
                    197:                 my ($ending,$emb,$descr)=split(/\s+/,$_,3);
                    198:                 if ($descr ne '') {
                    199:                     $fe{$ending}=lc($emb);
                    200:                     $fd{$ending}=$descr;
                    201:                 }
                    202:             }
                    203:             close($fh);
                    204:         }
1.12      harris41  205:     }
1.22      www       206:     &Apache::lonnet::logthis(
1.46      matthew   207:               "<font color=yellow>INFO: Read file types</font>");
1.22      www       208:     $readit=1;
1.46      matthew   209:     }  # end of unless($readit) 
1.32      matthew   210:     
                    211: }
1.112     bowersj2  212: 
1.42      matthew   213: ###############################################################
                    214: ##           HTML and Javascript Helper Functions            ##
                    215: ###############################################################
                    216: 
                    217: =pod 
                    218: 
1.112     bowersj2  219: =head1 HTML and Javascript Functions
1.42      matthew   220: 
1.112     bowersj2  221: =over 4
                    222: 
                    223: =item * browser_and_searcher_javascript ()
                    224: 
                    225: X<browsing, javascript>X<searching, javascript>Returns a string
                    226: containing javascript with two functions, C<openbrowser> and
                    227: C<opensearcher>. Returned string does not contain E<lt>scriptE<gt>
                    228: tags.
1.42      matthew   229: 
1.112     bowersj2  230: =item * openbrowser(formname,elementname,only,omit) [javascript]
1.42      matthew   231: 
                    232: inputs: formname, elementname, only, omit
                    233: 
                    234: formname and elementname indicate the name of the html form and name of
                    235: the element that the results of the browsing selection are to be placed in. 
                    236: 
                    237: Specifying 'only' will restrict the browser to displaying only files
1.185     www       238: with the given extension.  Can be a comma separated list.
1.42      matthew   239: 
                    240: Specifying 'omit' will restrict the browser to NOT displaying files
1.185     www       241: with the given extension.  Can be a comma separated list.
1.42      matthew   242: 
1.112     bowersj2  243: =item * opensearcher(formname, elementname) [javascript]
1.42      matthew   244: 
                    245: Inputs: formname, elementname
                    246: 
                    247: formname and elementname specify the name of the html form and the name
                    248: of the element the selection from the search results will be placed in.
                    249: 
                    250: =cut
                    251: 
                    252: sub browser_and_searcher_javascript {
1.199     albertel  253:     my ($mode)=@_;
                    254:     if (!defined($mode)) { $mode='edit'; }
1.170     www       255:     my $resurl=&lastresurl();
1.42      matthew   256:     return <<END;
1.50      matthew   257:     var editbrowser = null;
1.135     albertel  258:     function openbrowser(formname,elementname,only,omit,titleelement) {
1.170     www       259:         var url = '$resurl/?';
1.42      matthew   260:         if (editbrowser == null) {
                    261:             url += 'launch=1&';
                    262:         }
                    263:         url += 'catalogmode=interactive&';
1.199     albertel  264:         url += 'mode=$mode&';
1.42      matthew   265:         url += 'form=' + formname + '&';
                    266:         if (only != null) {
                    267:             url += 'only=' + only + '&';
                    268:         } 
                    269:         if (omit != null) {
                    270:             url += 'omit=' + omit + '&';
                    271:         }
1.135     albertel  272:         if (titleelement != null) {
                    273:             url += 'titleelement=' + titleelement + '&';
                    274:         }
1.42      matthew   275:         url += 'element=' + elementname + '';
                    276:         var title = 'Browser';
                    277:         var options = 'scrollbars=1,resizable=1,menubar=0';
                    278:         options += ',width=700,height=600';
                    279:         editbrowser = open(url,title,options,'1');
                    280:         editbrowser.focus();
                    281:     }
                    282:     var editsearcher;
1.135     albertel  283:     function opensearcher(formname,elementname,titleelement) {
1.42      matthew   284:         var url = '/adm/searchcat?';
                    285:         if (editsearcher == null) {
                    286:             url += 'launch=1&';
                    287:         }
                    288:         url += 'catalogmode=interactive&';
1.199     albertel  289:         url += 'mode=$mode&';
1.42      matthew   290:         url += 'form=' + formname + '&';
1.135     albertel  291:         if (titleelement != null) {
                    292:             url += 'titleelement=' + titleelement + '&';
                    293:         }
1.42      matthew   294:         url += 'element=' + elementname + '';
                    295:         var title = 'Search';
                    296:         var options = 'scrollbars=1,resizable=1,menubar=0';
                    297:         options += ',width=700,height=600';
                    298:         editsearcher = open(url,title,options,'1');
                    299:         editsearcher.focus();
                    300:     }
                    301: END
1.170     www       302: }
                    303: 
                    304: sub lastresurl {
                    305:     if ($ENV{'environment.lastresurl'}) {
                    306: 	return $ENV{'environment.lastresurl'}
                    307:     } else {
                    308: 	return '/res';
                    309:     }
                    310: }
                    311: 
                    312: sub storeresurl {
                    313:     my $resurl=&Apache::lonnet::clutter(shift);
                    314:     unless ($resurl=~/^\/res/) { return 0; }
                    315:     $resurl=~s/\/$//;
                    316:     &Apache::lonnet::put('environment',{'lastresurl' => $resurl});
                    317:     &Apache::lonnet::appenv('environment.lastresurl' => $resurl);
                    318:     return 1;
1.42      matthew   319: }
                    320: 
1.74      www       321: sub studentbrowser_javascript {
1.111     www       322:    unless (
                    323:             (($ENV{'request.course.id'}) && 
                    324:              (&Apache::lonnet::allowed('srm',$ENV{'request.course.id'})))
                    325:          || ($ENV{'request.role'}=~/^(au|dc|su)/)
                    326:           ) { return ''; }  
1.74      www       327:    return (<<'ENDSTDBRW');
                    328: <script type="text/javascript" language="Javascript" >
                    329:     var stdeditbrowser;
1.111     www       330:     function openstdbrowser(formname,uname,udom,roleflag) {
1.74      www       331:         var url = '/adm/pickstudent?';
                    332:         var filter;
                    333:         eval('filter=document.'+formname+'.'+uname+'.value;');
                    334:         if (filter != null) {
                    335:            if (filter != '') {
                    336:                url += 'filter='+filter+'&';
                    337: 	   }
                    338:         }
                    339:         url += 'form=' + formname + '&unameelement='+uname+
                    340:                                     '&udomelement='+udom;
1.111     www       341: 	if (roleflag) { url+="&roles=1"; }
1.102     www       342:         var title = 'Student_Browser';
1.74      www       343:         var options = 'scrollbars=1,resizable=1,menubar=0';
                    344:         options += ',width=700,height=600';
                    345:         stdeditbrowser = open(url,title,options,'1');
                    346:         stdeditbrowser.focus();
                    347:     }
                    348: </script>
                    349: ENDSTDBRW
                    350: }
1.42      matthew   351: 
1.74      www       352: sub selectstudent_link {
1.111     www       353:    my ($form,$unameele,$udomele)=@_;
                    354:    if ($ENV{'request.course.id'}) {  
                    355:        unless (&Apache::lonnet::allowed('srm',$ENV{'request.course.id'})) {
                    356: 	   return '';
                    357:        }
                    358:        return "<a href='".'javascript:openstdbrowser("'.$form.'","'.$unameele.
1.119     www       359:         '","'.$udomele.'");'."'>".&mt('Select User')."</a>";
1.74      www       360:    }
1.111     www       361:    if ($ENV{'request.role'}=~/^(au|dc|su)/) {
                    362:        return "<a href='".'javascript:openstdbrowser("'.$form.'","'.$unameele.
1.119     www       363:         '","'.$udomele.'",1);'."'>".&mt('Select User')."</a>";
1.111     www       364:    }
                    365:    return '';
1.91      www       366: }
                    367: 
                    368: sub coursebrowser_javascript {
1.128     albertel  369:     my ($domainfilter)=@_;
                    370:    return (<<ENDSTDBRW);
1.91      www       371: <script type="text/javascript" language="Javascript" >
                    372:     var stdeditbrowser;
1.187     albertel  373:     function opencrsbrowser(formname,uname,udom,desc) {
1.91      www       374:         var url = '/adm/pickcourse?';
                    375:         var filter;
                    376:         if (filter != null) {
                    377:            if (filter != '') {
                    378:                url += 'filter='+filter+'&';
                    379: 	   }
                    380:         }
1.128     albertel  381:         var domainfilter='$domainfilter';
                    382:         if (domainfilter != null) {
                    383:            if (domainfilter != '') {
                    384:                url += 'domainfilter='+domainfilter+'&';
                    385: 	   }
                    386:         }
1.91      www       387:         url += 'form=' + formname + '&cnumelement='+uname+
1.187     albertel  388: 	                            '&cdomelement='+udom+
                    389:                                     '&cnameelement='+desc;
1.102     www       390:         var title = 'Course_Browser';
1.91      www       391:         var options = 'scrollbars=1,resizable=1,menubar=0';
                    392:         options += ',width=700,height=600';
                    393:         stdeditbrowser = open(url,title,options,'1');
                    394:         stdeditbrowser.focus();
                    395:     }
                    396: </script>
                    397: ENDSTDBRW
                    398: }
                    399: 
                    400: sub selectcourse_link {
1.187     albertel  401:    my ($form,$unameele,$udomele,$desc)=@_;
1.91      www       402:     return "<a href='".'javascript:opencrsbrowser("'.$form.'","'.$unameele.
1.187     albertel  403:         '","'.$udomele.'","'.$desc.'");'."'>".&mt('Select Course')."</a>";
1.74      www       404: }
1.42      matthew   405: 
                    406: =pod
1.36      matthew   407: 
1.112     bowersj2  408: =item * linked_select_forms(...)
1.36      matthew   409: 
                    410: linked_select_forms returns a string containing a <script></script> block
                    411: and html for two <select> menus.  The select menus will be linked in that
                    412: changing the value of the first menu will result in new values being placed
                    413: in the second menu.  The values in the select menu will appear in alphabetical
                    414: order.
                    415: 
                    416: linked_select_forms takes the following ordered inputs:
                    417: 
                    418: =over 4
                    419: 
1.112     bowersj2  420: =item * $formname, the name of the <form> tag
1.36      matthew   421: 
1.112     bowersj2  422: =item * $middletext, the text which appears between the <select> tags
1.36      matthew   423: 
1.112     bowersj2  424: =item * $firstdefault, the default value for the first menu
1.36      matthew   425: 
1.112     bowersj2  426: =item * $firstselectname, the name of the first <select> tag
1.36      matthew   427: 
1.112     bowersj2  428: =item * $secondselectname, the name of the second <select> tag
1.36      matthew   429: 
1.112     bowersj2  430: =item * $hashref, a reference to a hash containing the data for the menus.
1.36      matthew   431: 
1.41      ng        432: =back 
                    433: 
1.36      matthew   434: Below is an example of such a hash.  Only the 'text', 'default', and 
                    435: 'select2' keys must appear as stated.  keys(%menu) are the possible 
                    436: values for the first select menu.  The text that coincides with the 
1.41      ng        437: first menu value is given in $menu{$choice1}->{'text'}.  The values 
1.36      matthew   438: and text for the second menu are given in the hash pointed to by 
                    439: $menu{$choice1}->{'select2'}.  
                    440: 
1.112     bowersj2  441:  my %menu = ( A1 => { text =>"Choice A1" ,
                    442:                        default => "B3",
                    443:                        select2 => { 
                    444:                            B1 => "Choice B1",
                    445:                            B2 => "Choice B2",
                    446:                            B3 => "Choice B3",
                    447:                            B4 => "Choice B4"
                    448:                            }
                    449:                    },
                    450:                A2 => { text =>"Choice A2" ,
                    451:                        default => "C2",
                    452:                        select2 => { 
                    453:                            C1 => "Choice C1",
                    454:                            C2 => "Choice C2",
                    455:                            C3 => "Choice C3"
                    456:                            }
                    457:                    },
                    458:                A3 => { text =>"Choice A3" ,
                    459:                        default => "D6",
                    460:                        select2 => { 
                    461:                            D1 => "Choice D1",
                    462:                            D2 => "Choice D2",
                    463:                            D3 => "Choice D3",
                    464:                            D4 => "Choice D4",
                    465:                            D5 => "Choice D5",
                    466:                            D6 => "Choice D6",
                    467:                            D7 => "Choice D7"
                    468:                            }
                    469:                    }
                    470:                );
1.36      matthew   471: 
                    472: =cut
                    473: 
                    474: sub linked_select_forms {
                    475:     my ($formname,
                    476:         $middletext,
                    477:         $firstdefault,
                    478:         $firstselectname,
                    479:         $secondselectname, 
                    480:         $hashref
                    481:         ) = @_;
                    482:     my $second = "document.$formname.$secondselectname";
                    483:     my $first = "document.$formname.$firstselectname";
                    484:     # output the javascript to do the changing
                    485:     my $result = '';
                    486:     $result.="<script>\n";
                    487:     $result.="var select2data = new Object();\n";
                    488:     $" = '","';
                    489:     my $debug = '';
                    490:     foreach my $s1 (sort(keys(%$hashref))) {
                    491:         $result.="select2data.d_$s1 = new Object();\n";        
                    492:         $result.="select2data.d_$s1.def = new String('".
                    493:             $hashref->{$s1}->{'default'}."');\n";
                    494:         $result.="select2data.d_$s1.values = new Array(";        
                    495:         my @s2values = sort(keys( %{ $hashref->{$s1}->{'select2'} } ));
                    496:         $result.="\"@s2values\");\n";
                    497:         $result.="select2data.d_$s1.texts = new Array(";        
                    498:         my @s2texts;
                    499:         foreach my $value (@s2values) {
                    500:             push @s2texts, $hashref->{$s1}->{'select2'}->{$value};
                    501:         }
                    502:         $result.="\"@s2texts\");\n";
                    503:     }
                    504:     $"=' ';
                    505:     $result.= <<"END";
                    506: 
                    507: function select1_changed() {
                    508:     // Determine new choice
                    509:     var newvalue = "d_" + $first.value;
                    510:     // update select2
                    511:     var values     = select2data[newvalue].values;
                    512:     var texts      = select2data[newvalue].texts;
                    513:     var select2def = select2data[newvalue].def;
                    514:     var i;
                    515:     // out with the old
                    516:     for (i = 0; i < $second.options.length; i++) {
                    517:         $second.options[i] = null;
                    518:     }
                    519:     // in with the nuclear
                    520:     for (i=0;i<values.length; i++) {
                    521:         $second.options[i] = new Option(values[i]);
1.143     matthew   522:         $second.options[i].value = values[i];
1.36      matthew   523:         $second.options[i].text = texts[i];
                    524:         if (values[i] == select2def) {
                    525:             $second.options[i].selected = true;
                    526:         }
                    527:     }
                    528: }
                    529: </script>
                    530: END
                    531:     # output the initial values for the selection lists
                    532:     $result .= "<select size=\"1\" name=\"$firstselectname\" onchange=\"select1_changed()\">\n";
                    533:     foreach my $value (sort(keys(%$hashref))) {
                    534:         $result.="    <option value=\"$value\" ";
                    535:         $result.=" selected=\"true\" " if ($value eq $firstdefault);
1.119     www       536:         $result.=">".&mt($hashref->{$value}->{'text'})."</option>\n";
1.36      matthew   537:     }
                    538:     $result .= "</select>\n";
                    539:     my %select2 = %{$hashref->{$firstdefault}->{'select2'}};
                    540:     $result .= $middletext;
                    541:     $result .= "<select size=\"1\" name=\"$secondselectname\">\n";
                    542:     my $seconddefault = $hashref->{$firstdefault}->{'default'};
                    543:     foreach my $value (sort(keys(%select2))) {
                    544:         $result.="    <option value=\"$value\" ";        
                    545:         $result.=" selected=\"true\" " if ($value eq $seconddefault);
1.119     www       546:         $result.=">".&mt($select2{$value})."</option>\n";
1.36      matthew   547:     }
                    548:     $result .= "</select>\n";
                    549:     #    return $debug;
                    550:     return $result;
                    551: }   #  end of sub linked_select_forms {
                    552: 
1.45      matthew   553: =pod
1.44      bowersj2  554: 
1.112     bowersj2  555: =item * help_open_topic($topic, $text, $stayOnPage, $width, $height)
1.44      bowersj2  556: 
1.112     bowersj2  557: Returns a string corresponding to an HTML link to the given help
                    558: $topic, where $topic corresponds to the name of a .tex file in
                    559: /home/httpd/html/adm/help/tex, with underscores replaced by
                    560: spaces. 
                    561: 
                    562: $text will optionally be linked to the same topic, allowing you to
                    563: link text in addition to the graphic. If you do not want to link
                    564: text, but wish to specify one of the later parameters, pass an
                    565: empty string. 
                    566: 
                    567: $stayOnPage is a value that will be interpreted as a boolean. If true,
                    568: the link will not open a new window. If false, the link will open
                    569: a new window using Javascript. (Default is false.) 
                    570: 
                    571: $width and $height are optional numerical parameters that will
                    572: override the width and height of the popped up window, which may
                    573: be useful for certain help topics with big pictures included. 
1.44      bowersj2  574: 
                    575: =cut
                    576: 
                    577: sub help_open_topic {
1.48      bowersj2  578:     my ($topic, $text, $stayOnPage, $width, $height) = @_;
                    579:     $text = "" if (not defined $text);
1.44      bowersj2  580:     $stayOnPage = 0 if (not defined $stayOnPage);
1.108     bowersj2  581:     if ($ENV{'browser.interface'} eq 'textual' ||
                    582: 	$ENV{'environment.remote'} eq 'off' ) {
1.79      www       583: 	$stayOnPage=1;
                    584:     }
1.44      bowersj2  585:     $width = 350 if (not defined $width);
                    586:     $height = 400 if (not defined $height);
                    587:     my $filename = $topic;
                    588:     $filename =~ s/ /_/g;
                    589: 
1.48      bowersj2  590:     my $template = "";
                    591:     my $link;
1.159     www       592: 
                    593:     $topic=~s/\W/\_/g;
1.44      bowersj2  594: 
                    595:     if (!$stayOnPage)
                    596:     {
1.72      bowersj2  597: 	$link = "javascript:void(open('/adm/help/${filename}.hlp', 'Help_for_$topic', 'menubar=0,toolbar=1,scrollbars=1,width=$width,height=$height,resizable=yes'))";
1.44      bowersj2  598:     }
                    599:     else
                    600:     {
1.48      bowersj2  601: 	$link = "/adm/help/${filename}.hlp";
                    602:     }
                    603: 
                    604:     # Add the text
                    605:     if ($text ne "")
                    606:     {
1.77      www       607: 	$template .= 
                    608:   "<table bgcolor='#3333AA' cellspacing='1' cellpadding='1' border='0'><tr>".
1.78      www       609:   "<td bgcolor='#5555FF'><a href=\"$link\"><font color='#FFFFFF' size='2'>$text</font></a>";
1.48      bowersj2  610:     }
                    611: 
                    612:     # Add the graphic
1.179     matthew   613:     my $title = &mt('Online Help');
1.48      bowersj2  614:     $template .= <<"ENDTEMPLATE";
1.179     matthew   615:  <a href="$link" title="$title"><image src="/adm/help/gif/smallHelp.gif" border="0" alt="(Help: $topic)" /></a>
1.44      bowersj2  616: ENDTEMPLATE
1.78      www       617:     if ($text ne '') { $template.='</td></tr></table>' };
1.44      bowersj2  618:     return $template;
                    619: 
1.106     bowersj2  620: }
                    621: 
                    622: # This is a quicky function for Latex cheatsheet editing, since it 
                    623: # appears in at least four places
                    624: sub helpLatexCheatsheet {
                    625:     my $other = shift;
                    626:     my $addOther = '';
                    627:     if ($other) {
                    628: 	$addOther = Apache::loncommon::help_open_topic($other, shift,
                    629: 						       undef, undef, 600) .
                    630: 							   '</td><td>';
                    631:     }
                    632:     return '<table><tr><td>'.
                    633: 	$addOther .
                    634: 	&Apache::loncommon::help_open_topic("Greek_Symbols",'Greek Symbols',
                    635: 					    undef,undef,600)
                    636: 	.'</td><td>'.
                    637: 	&Apache::loncommon::help_open_topic("Other_Symbols",'Other Symbols',
                    638: 					    undef,undef,600)
                    639: 	.'</td></tr></table>';
1.172     www       640: }
                    641: 
1.193     raeburn   642: sub help_open_menu {
                    643:     my ($color,$topic,$component_help,$function,$faq,$bug,$stayOnPage,$width,$height,$text) = @_;
                    644:     $text = "" if (not defined $text);
                    645:     $stayOnPage = 0 if (not defined $stayOnPage);
                    646:     if ($ENV{'browser.interface'} eq 'textual' ||
                    647:         $ENV{'environment.remote'} eq 'off' ) {
                    648:         $stayOnPage=1;
                    649:     }
                    650:     $width = 620 if (not defined $width);
                    651:     $height = 600 if (not defined $height);
                    652:     my $link='';
1.201     raeburn   653:     my $title = &mt('Get help');
1.193     raeburn   654:     my $origurl = $ENV{'REQUEST_URI'};
                    655:     my $timestamp = time;
                    656:     foreach (\$color,\$function,\$topic,\$component_help,\$faq,\$bug,\$origurl) {
                    657:         $$_ = &Apache::lonnet::escape($$_);
                    658:     }
                    659: 
1.195     albertel  660:     if (!$stayOnPage) {
1.193     raeburn   661:          $link = "javascript:helpMenu('open')";
1.195     albertel  662:     } else {
1.193     raeburn   663:         $link = "javascript:helpMenu('display')";
                    664:     }
1.198     raeburn   665:     my $banner_link = "/adm/helpmenu?page=banner&color=$color&function=$function&topic=$topic&component_help=$component_help&faq=$faq&bug=$bug&origurl=$origurl&stamp=$timestamp&stayonpage=$stayOnPage";
1.193     raeburn   666:     my $details_link = "/adm/helpmenu?page=body&color=$color&function=$function&topic=$topic&component_help=$component_help&faq=$faq&bug=$bug&origurl=$origurl&stamp=$timestamp";
1.196     albertel  667:     my $template;
                    668:     if ($text ne "") {
                    669: 	$template .= 
                    670:   "<table bgcolor='#337733' cellspacing='1' cellpadding='1' border='0'><tr>".
                    671:   "<td bgcolor='#448844'><a href=\"$link\"><font color='#FFFFFF' size='2'>$text</font></a>";
                    672:     }
                    673:     $template .= <<"ENDTEMPLATE";
1.193     raeburn   674:  <script>
                    675: function helpMenu(caller) {
                    676:     if (caller == 'open') {
                    677:         newWindow =  window.open("","helpmenu","HEIGHT=$height,WIDTH=$width,resize=yes,scrollbars=yes" )
                    678:         caller = newWindow.document
                    679:     } else {
                    680:         caller = this.document
                    681:     }
                    682:     caller.write("<html><head><title>LON-CAPA Help Menu</title><meta http-equiv='pragma' content='no-cache'></head>")
                    683:     caller.write("<frameset rows='105,*' border='0'><frame name='bannerframe'  src='$banner_link'><frame name='bodyframe' src='$details_link'></frameset>")
                    684:     caller.write("</html>")
                    685:     caller.close()
                    686:     if (caller == newWindow.document) {
                    687:         caller.focus()
                    688:     }
                    689: }
                    690:  </script>
1.204     raeburn   691:  <a href="$link" title="$title"><image src="/adm/lonIcons/helpgateway.gif" border="0" alt="(Help Menu)" /></a>
1.193     raeburn   692: ENDTEMPLATE
1.203     albertel  693:     if ($component_help) {
                    694: 	if (!$text) {
                    695: 	    $template=&help_open_topic($component_help,undef,$stayOnPage,
                    696: 				       $width,$height).' '.$template;
                    697: 	} else {
                    698: 	    my $help_text;
                    699: 	    $help_text=&Apache::lonnet::unescape($topic);
                    700: 	    $template='<table><tr><td>'.
                    701: 		&help_open_topic($component_help,$help_text,$stayOnPage,
                    702: 				 $width,$height).'</td><td>'.$template.
                    703: 				 '</td></tr></table>';
                    704: 	}
                    705:     }
1.196     albertel  706:     if ($text ne '') { $template.='</td></tr></table>' };
1.193     raeburn   707:     return $template;
                    708: }
                    709: 
1.172     www       710: sub help_open_bug {
                    711:     my ($topic, $text, $stayOnPage, $width, $height) = @_;
                    712:     unless ($ENV{'user.adv'}) { return ''; }
                    713:     unless ($Apache::lonnet::perlvar{'BugzillaHost'}) { return ''; }
                    714:     $text = "" if (not defined $text);
                    715:     $stayOnPage = 0 if (not defined $stayOnPage);
                    716:     if ($ENV{'browser.interface'} eq 'textual' ||
                    717: 	$ENV{'environment.remote'} eq 'off' ) {
                    718: 	$stayOnPage=1;
                    719:     }
1.184     albertel  720:     $width = 600 if (not defined $width);
                    721:     $height = 600 if (not defined $height);
1.172     www       722: 
                    723:     $topic=~s/\W+/\+/g;
                    724:     my $link='';
                    725:     my $template='';
                    726:     my $url=$Apache::lonnet::perlvar{'BugzillaHost'}.'enter_bug.cgi?product=LON-CAPA&bug_file_loc='.
                    727: 	&Apache::lonnet::escape($ENV{'REQUEST_URI'}).'&component='.$topic;
                    728:     if (!$stayOnPage)
                    729:     {
                    730: 	$link = "javascript:void(open('$url', 'Bugzilla', 'menubar=0,toolbar=1,scrollbars=1,width=$width,height=$height,resizable=yes'))";
                    731:     }
                    732:     else
                    733:     {
                    734: 	$link = $url;
                    735:     }
                    736:     # Add the text
                    737:     if ($text ne "")
                    738:     {
                    739: 	$template .= 
                    740:   "<table bgcolor='#AA3333' cellspacing='1' cellpadding='1' border='0'><tr>".
                    741:   "<td bgcolor='#FF5555'><a href=\"$link\"><font color='#FFFFFF' size='2'>$text</font></a>";
                    742:     }
                    743: 
                    744:     # Add the graphic
1.179     matthew   745:     my $title = &mt('Report a Bug');
1.172     www       746:     $template .= <<"ENDTEMPLATE";
1.179     matthew   747:  <a href="$link" title="$title"><image src="/adm/lonMisc/smallBug.gif" border="0" alt="(Bug: $topic)" /></a>
1.172     www       748: ENDTEMPLATE
                    749:     if ($text ne '') { $template.='</td></tr></table>' };
                    750:     return $template;
                    751: 
                    752: }
                    753: 
                    754: sub help_open_faq {
                    755:     my ($topic, $text, $stayOnPage, $width, $height) = @_;
                    756:     unless ($ENV{'user.adv'}) { return ''; }
                    757:     unless ($Apache::lonnet::perlvar{'FAQHost'}) { return ''; }
                    758:     $text = "" if (not defined $text);
                    759:     $stayOnPage = 0 if (not defined $stayOnPage);
                    760:     if ($ENV{'browser.interface'} eq 'textual' ||
                    761: 	$ENV{'environment.remote'} eq 'off' ) {
                    762: 	$stayOnPage=1;
                    763:     }
                    764:     $width = 350 if (not defined $width);
                    765:     $height = 400 if (not defined $height);
                    766: 
                    767:     $topic=~s/\W+/\+/g;
                    768:     my $link='';
                    769:     my $template='';
                    770:     my $url=$Apache::lonnet::perlvar{'FAQHost'}.'/fom/cache/'.$topic.'.html';
                    771:     if (!$stayOnPage)
                    772:     {
                    773: 	$link = "javascript:void(open('$url', 'FAQ-O-Matic', 'menubar=0,toolbar=1,scrollbars=1,width=$width,height=$height,resizable=yes'))";
                    774:     }
                    775:     else
                    776:     {
                    777: 	$link = $url;
                    778:     }
                    779: 
                    780:     # Add the text
                    781:     if ($text ne "")
                    782:     {
                    783: 	$template .= 
1.173     www       784:   "<table bgcolor='#337733' cellspacing='1' cellpadding='1' border='0'><tr>".
                    785:   "<td bgcolor='#448844'><a href=\"$link\"><font color='#FFFFFF' size='2'>$text</font></a>";
1.172     www       786:     }
                    787: 
                    788:     # Add the graphic
1.179     matthew   789:     my $title = &mt('View the FAQ');
1.172     www       790:     $template .= <<"ENDTEMPLATE";
1.179     matthew   791:  <a href="$link" title="$title"><image src="/adm/lonMisc/smallFAQ.gif" border="0" alt="(FAQ: $topic)" /></a>
1.172     www       792: ENDTEMPLATE
                    793:     if ($text ne '') { $template.='</td></tr></table>' };
                    794:     return $template;
                    795: 
1.44      bowersj2  796: }
1.37      matthew   797: 
1.180     matthew   798: ###############################################################
                    799: ###############################################################
                    800: 
1.45      matthew   801: =pod
                    802: 
1.112     bowersj2  803: =item * csv_translate($text) 
1.37      matthew   804: 
1.185     www       805: Translate $text to allow it to be output as a 'comma separated values' 
1.37      matthew   806: format.
                    807: 
                    808: =cut
                    809: 
1.180     matthew   810: ###############################################################
                    811: ###############################################################
1.37      matthew   812: sub csv_translate {
                    813:     my $text = shift;
                    814:     $text =~ s/\"/\"\"/g;
                    815:     $text =~ s/\n//g;
                    816:     return $text;
                    817: }
1.180     matthew   818: 
                    819: 
                    820: ###############################################################
                    821: ###############################################################
                    822: 
                    823: =pod
                    824: 
                    825: =item * define_excel_formats
                    826: 
                    827: Define some commonly used Excel cell formats.
                    828: 
                    829: Currently supported formats:
                    830: 
                    831: =over 4
                    832: 
                    833: =item header
                    834: 
                    835: =item bold
                    836: 
                    837: =item h1
                    838: 
                    839: =item h2
                    840: 
                    841: =item h3
                    842: 
                    843: =item date
                    844: 
                    845: =back
                    846: 
                    847: Inputs: $workbook
                    848: 
                    849: Returns: $format, a hash reference.
                    850: 
                    851: =cut
                    852: 
                    853: ###############################################################
                    854: ###############################################################
                    855: sub define_excel_formats {
                    856:     my ($workbook) = @_;
                    857:     my $format;
                    858:     $format->{'header'} = $workbook->add_format(bold      => 1, 
                    859:                                                 bottom    => 1,
                    860:                                                 align     => 'center');
                    861:     $format->{'bold'} = $workbook->add_format(bold=>1);
                    862:     $format->{'h1'}   = $workbook->add_format(bold=>1, size=>18);
                    863:     $format->{'h2'}   = $workbook->add_format(bold=>1, size=>16);
                    864:     $format->{'h3'}   = $workbook->add_format(bold=>1, size=>14);
                    865:     $format->{'date'} = $workbook->add_format(num_format=>
1.207     matthew   866:                                             'mm/dd/yyyy hh:mm:ss');
1.180     matthew   867:     return $format;
                    868: }
                    869: 
                    870: ###############################################################
                    871: ###############################################################
1.113     bowersj2  872: 
                    873: =pod
                    874: 
                    875: =item * change_content_javascript():
                    876: 
                    877: This and the next function allow you to create small sections of an
                    878: otherwise static HTML page that you can update on the fly with
                    879: Javascript, even in Netscape 4.
                    880: 
                    881: The Javascript fragment returned by this function (no E<lt>scriptE<gt> tag)
                    882: must be written to the HTML page once. It will prove the Javascript
                    883: function "change(name, content)". Calling the change function with the
                    884: name of the section 
                    885: you want to update, matching the name passed to C<changable_area>, and
                    886: the new content you want to put in there, will put the content into
                    887: that area.
                    888: 
                    889: B<Note>: Netscape 4 only reserves enough space for the changable area
                    890: to contain room for the original contents. You need to "make space"
                    891: for whatever changes you wish to make, and be B<sure> to check your
                    892: code in Netscape 4. This feature in Netscape 4 is B<not> powerful;
                    893: it's adequate for updating a one-line status display, but little more.
                    894: This script will set the space to 100% width, so you only need to
                    895: worry about height in Netscape 4.
                    896: 
                    897: Modern browsers are much less limiting, and if you can commit to the
                    898: user not using Netscape 4, this feature may be used freely with
                    899: pretty much any HTML.
                    900: 
                    901: =cut
                    902: 
                    903: sub change_content_javascript {
                    904:     # If we're on Netscape 4, we need to use Layer-based code
                    905:     if ($ENV{'browser.type'} eq 'netscape' &&
                    906: 	$ENV{'browser.version'} =~ /^4\./) {
                    907: 	return (<<NETSCAPE4);
                    908: 	function change(name, content) {
                    909: 	    doc = document.layers[name+"___escape"].layers[0].document;
                    910: 	    doc.open();
                    911: 	    doc.write(content);
                    912: 	    doc.close();
                    913: 	}
                    914: NETSCAPE4
                    915:     } else {
                    916: 	# Otherwise, we need to use semi-standards-compliant code
                    917: 	# (technically, "innerHTML" isn't standard but the equivalent
                    918: 	# is really scary, and every useful browser supports it
                    919: 	return (<<DOMBASED);
                    920: 	function change(name, content) {
                    921: 	    element = document.getElementById(name);
                    922: 	    element.innerHTML = content;
                    923: 	}
                    924: DOMBASED
                    925:     }
                    926: }
                    927: 
                    928: =pod
                    929: 
                    930: =item * changable_area($name, $origContent):
                    931: 
                    932: This provides a "changable area" that can be modified on the fly via
                    933: the Javascript code provided in C<change_content_javascript>. $name is
                    934: the name you will use to reference the area later; do not repeat the
                    935: same name on a given HTML page more then once. $origContent is what
                    936: the area will originally contain, which can be left blank.
                    937: 
                    938: =cut
                    939: 
                    940: sub changable_area {
                    941:     my ($name, $origContent) = @_;
                    942: 
                    943:     if ($ENV{'browser.type'} eq 'netscape' &&
                    944: 	$ENV{'browser.version'} =~ /^4\./) {
                    945: 	# If this is netscape 4, we need to use the Layer tag
                    946: 	return "<ilayer width='100%' id='${name}___escape' overflow='none'><layer width='100%' id='$name' overflow='none'>$origContent</layer></ilayer>";
                    947:     } else {
                    948: 	return "<span id='$name'>$origContent</span>";
                    949:     }
                    950: }
                    951: 
                    952: =pod
                    953: 
                    954: =back
                    955: 
                    956: =cut
1.37      matthew   957: 
                    958: ###############################################################
1.33      matthew   959: ##        Home server <option> list generating code          ##
                    960: ###############################################################
1.35      matthew   961: 
1.45      matthew   962: =pod
                    963: 
1.112     bowersj2  964: =head1 Home Server option list generating code
                    965: 
                    966: =over 4
                    967: 
                    968: =item * get_domains()
1.35      matthew   969: 
                    970: Returns an array containing each of the domains listed in the hosts.tab
                    971: file.
                    972: 
                    973: =cut
                    974: 
                    975: #-------------------------------------------
1.34      matthew   976: sub get_domains {
                    977:     # The code below was stolen from "The Perl Cookbook", p 102, 1st ed.
                    978:     my @domains;
                    979:     my %seen;
                    980:     foreach (sort values(%Apache::lonnet::hostdom)) {
1.169     www       981: 	push (@domains,$_) unless $seen{$_}++;
1.34      matthew   982:     }
                    983:     return @domains;
                    984: }
1.88      www       985: 
1.169     www       986: # ------------------------------------------
                    987: 
                    988: sub domain_select {
                    989:     my ($name,$value,$multiple)=@_;
                    990:     my %domains=map { 
                    991: 	$_ => $_.' '.$Apache::lonnet::domaindescription{$_} 
                    992:     } &get_domains;
                    993:     if ($multiple) {
                    994: 	$domains{''}=&mt('Any domain');
1.191     matthew   995: 	return &multiple_select_form($name,$value,4,%domains);
1.169     www       996:     } else {
                    997: 	return &select_form($name,$value,%domains);
                    998:     }
                    999: }
                   1000: 
                   1001: sub multiple_select_form {
1.191     matthew  1002:     my ($name,$value,$size,%hash)=@_;
1.169     www      1003:     my %selected = map { $_ => 1 } ref($value)?@{$value}:($value);
                   1004:     my $output='';
1.191     matthew  1005:     if (! defined($size)) {
                   1006:         $size = 4;
                   1007:         if (scalar(keys(%hash))<4) {
                   1008:             $size = scalar(keys(%hash));
                   1009:         }
                   1010:     }
1.169     www      1011:     $output.="\n<select name='$name' size='$size' multiple='1'>";
1.191     matthew  1012:     foreach (sort(keys(%hash))) {
                   1013:         $output.='<option value="'.$_.'" ';
                   1014:         $output.='selected ' if ($selected{$_});
                   1015:         $output.='>'.$hash{$_}."</option>\n";
1.169     www      1016:     }
                   1017:     $output.="</select>\n";
                   1018:     return $output;
                   1019: }
                   1020: 
1.88      www      1021: #-------------------------------------------
                   1022: 
                   1023: =pod
                   1024: 
1.112     bowersj2 1025: =item * select_form($defdom,$name,%hash)
1.88      www      1026: 
                   1027: Returns a string containing a <select name='$name' size='1'> form to 
                   1028: allow a user to select options from a hash option_name => displayed text.  
                   1029: See lonrights.pm for an example invocation and use.
                   1030: 
                   1031: =cut
                   1032: 
                   1033: #-------------------------------------------
                   1034: sub select_form {
                   1035:     my ($def,$name,%hash) = @_;
                   1036:     my $selectform = "<select name=\"$name\" size=\"1\">\n";
1.128     albertel 1037:     my @keys;
                   1038:     if (exists($hash{'select_form_order'})) {
                   1039: 	@keys=@{$hash{'select_form_order'}};
                   1040:     } else {
                   1041: 	@keys=sort(keys(%hash));
                   1042:     }
                   1043:     foreach (@keys) {
1.88      www      1044:         $selectform.="<option value=\"$_\" ".
                   1045:             ($_ eq $def ? 'selected' : '').
1.119     www      1046:                 ">".&mt($hash{$_})."</option>\n";
1.88      www      1047:     }
                   1048:     $selectform.="</select>";
                   1049:     return $selectform;
                   1050: }
                   1051: 
1.167     www      1052: sub gradeleveldescription {
                   1053:     my $gradelevel=shift;
                   1054:     my %gradelevels=(0 => 'Not specified',
                   1055: 		     1 => 'Grade 1',
                   1056: 		     2 => 'Grade 2',
                   1057: 		     3 => 'Grade 3',
                   1058: 		     4 => 'Grade 4',
                   1059: 		     5 => 'Grade 5',
                   1060: 		     6 => 'Grade 6',
                   1061: 		     7 => 'Grade 7',
                   1062: 		     8 => 'Grade 8',
                   1063: 		     9 => 'Grade 9',
                   1064: 		     10 => 'Grade 10',
                   1065: 		     11 => 'Grade 11',
                   1066: 		     12 => 'Grade 12',
                   1067: 		     13 => 'Grade 13',
                   1068: 		     14 => '100 Level',
                   1069: 		     15 => '200 Level',
                   1070: 		     16 => '300 Level',
                   1071: 		     17 => '400 Level',
                   1072: 		     18 => 'Graduate Level');
                   1073:     return &mt($gradelevels{$gradelevel});
                   1074: }
                   1075: 
1.163     www      1076: sub select_level_form {
                   1077:     my ($deflevel,$name)=@_;
                   1078:     unless ($deflevel) { $deflevel=0; }
1.167     www      1079:     my $selectform = "<select name=\"$name\" size=\"1\">\n";
                   1080:     for (my $i=0; $i<=18; $i++) {
                   1081:         $selectform.="<option value=\"$i\" ".
                   1082:             ($i==$deflevel ? 'selected' : '').
                   1083:                 ">".&gradeleveldescription($i)."</option>\n";
                   1084:     }
                   1085:     $selectform.="</select>";
                   1086:     return $selectform;
1.163     www      1087: }
1.167     www      1088: 
1.35      matthew  1089: #-------------------------------------------
                   1090: 
1.45      matthew  1091: =pod
                   1092: 
1.112     bowersj2 1093: =item * select_dom_form($defdom,$name,$includeempty)
1.35      matthew  1094: 
                   1095: Returns a string containing a <select name='$name' size='1'> form to 
                   1096: allow a user to select the domain to preform an operation in.  
                   1097: See loncreateuser.pm for an example invocation and use.
                   1098: 
1.90      www      1099: If the $includeempty flag is set, it also includes an empty choice ("no domain
                   1100: selected");
                   1101: 
1.35      matthew  1102: =cut
                   1103: 
                   1104: #-------------------------------------------
1.34      matthew  1105: sub select_dom_form {
1.90      www      1106:     my ($defdom,$name,$includeempty) = @_;
1.34      matthew  1107:     my @domains = get_domains();
1.90      www      1108:     if ($includeempty) { @domains=('',@domains); }
1.34      matthew  1109:     my $selectdomain = "<select name=\"$name\" size=\"1\">\n";
                   1110:     foreach (@domains) {
                   1111:         $selectdomain.="<option value=\"$_\" ".
                   1112:             ($_ eq $defdom ? 'selected' : '').
                   1113:                 ">$_</option>\n";
                   1114:     }
                   1115:     $selectdomain.="</select>";
                   1116:     return $selectdomain;
                   1117: }
                   1118: 
1.35      matthew  1119: #-------------------------------------------
                   1120: 
1.45      matthew  1121: =pod
                   1122: 
1.112     bowersj2 1123: =item * get_library_servers($domain)
1.35      matthew  1124: 
                   1125: Returns a hash which contains keys like '103l3' and values like 
                   1126: 'kirk.lite.msu.edu'.  All of the keys will be for machines in the
                   1127: given $domain.
                   1128: 
                   1129: =cut
                   1130: 
                   1131: #-------------------------------------------
1.52      matthew  1132: sub get_library_servers {
1.33      matthew  1133:     my $domain = shift;
1.52      matthew  1134:     my %library_servers;
1.33      matthew  1135:     foreach (keys(%Apache::lonnet::libserv)) {
                   1136:         if ($Apache::lonnet::hostdom{$_} eq $domain) {
1.52      matthew  1137:             $library_servers{$_} = $Apache::lonnet::hostname{$_};
1.33      matthew  1138:         }
                   1139:     }
1.52      matthew  1140:     return %library_servers;
1.33      matthew  1141: }
                   1142: 
1.35      matthew  1143: #-------------------------------------------
                   1144: 
1.45      matthew  1145: =pod
                   1146: 
1.112     bowersj2 1147: =item * home_server_option_list($domain)
1.35      matthew  1148: 
                   1149: returns a string which contains an <option> list to be used in a 
                   1150: <select> form input.  See loncreateuser.pm for an example.
                   1151: 
                   1152: =cut
                   1153: 
                   1154: #-------------------------------------------
1.33      matthew  1155: sub home_server_option_list {
                   1156:     my $domain = shift;
1.52      matthew  1157:     my %servers = &get_library_servers($domain);
1.33      matthew  1158:     my $result = '';
                   1159:     foreach (sort keys(%servers)) {
                   1160:         $result.=
                   1161:             '<option value="'.$_.'">'.$_.' '.$servers{$_}."</option>\n";
                   1162:     }
                   1163:     return $result;
                   1164: }
1.112     bowersj2 1165: 
                   1166: =pod
                   1167: 
                   1168: =back
                   1169: 
                   1170: =cut
1.87      matthew  1171: 
                   1172: ###############################################################
1.112     bowersj2 1173: ##                  Decoding User Agent                      ##
1.87      matthew  1174: ###############################################################
                   1175: 
                   1176: =pod
                   1177: 
1.112     bowersj2 1178: =head1 Decoding the User Agent
                   1179: 
                   1180: =over 4
                   1181: 
                   1182: =item * &decode_user_agent()
1.87      matthew  1183: 
                   1184: Inputs: $r
                   1185: 
                   1186: Outputs:
                   1187: 
                   1188: =over 4
                   1189: 
1.112     bowersj2 1190: =item * $httpbrowser
1.87      matthew  1191: 
1.112     bowersj2 1192: =item * $clientbrowser
1.87      matthew  1193: 
1.112     bowersj2 1194: =item * $clientversion
1.87      matthew  1195: 
1.112     bowersj2 1196: =item * $clientmathml
1.87      matthew  1197: 
1.112     bowersj2 1198: =item * $clientunicode
1.87      matthew  1199: 
1.112     bowersj2 1200: =item * $clientos
1.87      matthew  1201: 
                   1202: =back
                   1203: 
1.157     matthew  1204: =back 
                   1205: 
1.87      matthew  1206: =cut
                   1207: 
                   1208: ###############################################################
                   1209: ###############################################################
                   1210: sub decode_user_agent {
                   1211:     my @browsertype=split(/\&/,$Apache::lonnet::perlvar{"lonBrowsDet"});
                   1212:     my %mathcap=split(/\&/,$$Apache::lonnet::perlvar{"lonMathML"});
                   1213:     my $httpbrowser=$ENV{"HTTP_USER_AGENT"};
                   1214:     my $clientbrowser='unknown';
                   1215:     my $clientversion='0';
                   1216:     my $clientmathml='';
                   1217:     my $clientunicode='0';
                   1218:     for (my $i=0;$i<=$#browsertype;$i++) {
                   1219:         my ($bname,$match,$notmatch,$vreg,$minv,$univ)=split(/\:/,$browsertype[$i]);
                   1220: 	if (($httpbrowser=~/$match/i)  && ($httpbrowser!~/$notmatch/i)) {
                   1221: 	    $clientbrowser=$bname;
                   1222:             $httpbrowser=~/$vreg/i;
                   1223: 	    $clientversion=$1;
                   1224:             $clientmathml=($clientversion>=$minv);
                   1225:             $clientunicode=($clientversion>=$univ);
                   1226: 	}
                   1227:     }
                   1228:     my $clientos='unknown';
                   1229:     if (($httpbrowser=~/linux/i) ||
                   1230:         ($httpbrowser=~/unix/i) ||
                   1231:         ($httpbrowser=~/ux/i) ||
                   1232:         ($httpbrowser=~/solaris/i)) { $clientos='unix'; }
                   1233:     if (($httpbrowser=~/vax/i) ||
                   1234:         ($httpbrowser=~/vms/i)) { $clientos='vms'; }
                   1235:     if ($httpbrowser=~/next/i) { $clientos='next'; }
                   1236:     if (($httpbrowser=~/mac/i) ||
                   1237:         ($httpbrowser=~/powerpc/i)) { $clientos='mac'; }
                   1238:     if ($httpbrowser=~/win/i) { $clientos='win'; }
                   1239:     if ($httpbrowser=~/embed/i) { $clientos='pda'; }
                   1240:     return ($httpbrowser,$clientbrowser,$clientversion,$clientmathml,
                   1241:             $clientunicode,$clientos,);
                   1242: }
                   1243: 
1.32      matthew  1244: ###############################################################
                   1245: ##    Authentication changing form generation subroutines    ##
                   1246: ###############################################################
                   1247: ##
                   1248: ## All of the authform_xxxxxxx subroutines take their inputs in a
                   1249: ## hash, and have reasonable default values.
                   1250: ##
                   1251: ##    formname = the name given in the <form> tag.
1.35      matthew  1252: #-------------------------------------------
                   1253: 
1.45      matthew  1254: =pod
                   1255: 
1.112     bowersj2 1256: =head1 Authentication Routines
                   1257: 
                   1258: =over 4
                   1259: 
                   1260: =item * authform_xxxxxx
1.35      matthew  1261: 
                   1262: The authform_xxxxxx subroutines provide javascript and html forms which 
                   1263: handle some of the conveniences required for authentication forms.  
                   1264: This is not an optimal method, but it works.  
                   1265: 
                   1266: See loncreateuser.pm for invocation and use examples.
                   1267: 
                   1268: =over 4
                   1269: 
1.112     bowersj2 1270: =item * authform_header
1.35      matthew  1271: 
1.112     bowersj2 1272: =item * authform_authorwarning
1.35      matthew  1273: 
1.112     bowersj2 1274: =item * authform_nochange
1.35      matthew  1275: 
1.112     bowersj2 1276: =item * authform_kerberos
1.35      matthew  1277: 
1.112     bowersj2 1278: =item * authform_internal
1.35      matthew  1279: 
1.112     bowersj2 1280: =item * authform_filesystem
1.35      matthew  1281: 
                   1282: =back
                   1283: 
1.157     matthew  1284: =back 
                   1285: 
1.35      matthew  1286: =cut
                   1287: 
                   1288: #-------------------------------------------
1.32      matthew  1289: sub authform_header{  
                   1290:     my %in = (
                   1291:         formname => 'cu',
1.80      albertel 1292:         kerb_def_dom => '',
1.32      matthew  1293:         @_,
                   1294:     );
                   1295:     $in{'formname'} = 'document.' . $in{'formname'};
                   1296:     my $result='';
1.80      albertel 1297: 
                   1298: #---------------------------------------------- Code for upper case translation
                   1299:     my $Javascript_toUpperCase;
                   1300:     unless ($in{kerb_def_dom}) {
                   1301:         $Javascript_toUpperCase =<<"END";
                   1302:         switch (choice) {
                   1303:            case 'krb': currentform.elements[choicearg].value =
                   1304:                currentform.elements[choicearg].value.toUpperCase();
                   1305:                break;
                   1306:            default:
                   1307:         }
                   1308: END
                   1309:     } else {
                   1310:         $Javascript_toUpperCase = "";
                   1311:     }
                   1312: 
1.165     raeburn  1313:     my $radioval = "'nochange'";
1.174     matthew  1314:     if (exists($in{'curr_authtype'}) &&
                   1315:         defined($in{'curr_authtype'}) &&
                   1316:         $in{'curr_authtype'} ne '') {
                   1317:         $radioval = "'$in{'curr_authtype'}arg'";
                   1318:     }
1.165     raeburn  1319:     my $argfield = 'null';
                   1320:     if ( grep/^mode$/,(keys %in) ) {
                   1321:         if ($in{'mode'} eq 'modifycourse')  {
                   1322:             if ( grep/^curr_authtype$/,(keys %in) ) {
                   1323:                 $radioval = "'$in{'curr_authtype'}'";
                   1324:             }
                   1325:             if ( grep/^curr_autharg$/,(keys %in) ) {
                   1326:                 unless ($in{'curr_autharg'} eq '') {
                   1327:                     $argfield = "'$in{'curr_autharg'}'";
                   1328:                 }
                   1329:             }
                   1330:         }
                   1331:     }
                   1332: 
1.32      matthew  1333:     $result.=<<"END";
                   1334: var current = new Object();
1.165     raeburn  1335: current.radiovalue = $radioval;
                   1336: current.argfield = $argfield;
1.32      matthew  1337: 
                   1338: function changed_radio(choice,currentform) {
                   1339:     var choicearg = choice + 'arg';
                   1340:     // If a radio button in changed, we need to change the argfield
                   1341:     if (current.radiovalue != choice) {
                   1342:         current.radiovalue = choice;
                   1343:         if (current.argfield != null) {
                   1344:             currentform.elements[current.argfield].value = '';
                   1345:         }
                   1346:         if (choice == 'nochange') {
                   1347:             current.argfield = null;
                   1348:         } else {
                   1349:             current.argfield = choicearg;
                   1350:             switch(choice) {
                   1351:                 case 'krb': 
                   1352:                     currentform.elements[current.argfield].value = 
                   1353:                         "$in{'kerb_def_dom'}";
                   1354:                 break;
                   1355:               default:
                   1356:                 break;
                   1357:             }
                   1358:         }
                   1359:     }
                   1360:     return;
                   1361: }
1.22      www      1362: 
1.32      matthew  1363: function changed_text(choice,currentform) {
                   1364:     var choicearg = choice + 'arg';
                   1365:     if (currentform.elements[choicearg].value !='') {
1.80      albertel 1366:         $Javascript_toUpperCase
1.32      matthew  1367:         // clear old field
                   1368:         if ((current.argfield != choicearg) && (current.argfield != null)) {
                   1369:             currentform.elements[current.argfield].value = '';
                   1370:         }
                   1371:         current.argfield = choicearg;
                   1372:     }
                   1373:     set_auth_radio_buttons(choice,currentform);
                   1374:     return;
1.20      www      1375: }
1.32      matthew  1376: 
                   1377: function set_auth_radio_buttons(newvalue,currentform) {
                   1378:     var i=0;
                   1379:     while (i < currentform.login.length) {
                   1380:         if (currentform.login[i].value == newvalue) { break; }
                   1381:         i++;
                   1382:     }
                   1383:     if (i == currentform.login.length) {
                   1384:         return;
                   1385:     }
                   1386:     current.radiovalue = newvalue;
                   1387:     currentform.login[i].checked = true;
                   1388:     return;
                   1389: }
                   1390: END
                   1391:     return $result;
                   1392: }
                   1393: 
                   1394: sub authform_authorwarning{
                   1395:     my $result='';
1.144     matthew  1396:     $result='<i>'.
                   1397:         &mt('As a general rule, only authors or co-authors should be '.
                   1398:             'filesystem authenticated '.
                   1399:             '(which allows access to the server filesystem).')."</i>\n";
1.32      matthew  1400:     return $result;
                   1401: }
                   1402: 
                   1403: sub authform_nochange{  
                   1404:     my %in = (
                   1405:               formname => 'document.cu',
                   1406:               kerb_def_dom => 'MSU.EDU',
                   1407:               @_,
                   1408:           );
1.144     matthew  1409:     my $result = &mt('[_1] Do not change login data',
                   1410:                      '<input type="radio" name="login" value="nochange" '.
                   1411:                      'checked="checked" onclick="'.
                   1412:             "javascript:changed_radio('nochange',$in{'formname'});".'" />');
1.32      matthew  1413:     return $result;
                   1414: }
                   1415: 
                   1416: sub authform_kerberos{  
                   1417:     my %in = (
                   1418:               formname => 'document.cu',
                   1419:               kerb_def_dom => 'MSU.EDU',
1.80      albertel 1420:               kerb_def_auth => 'krb4',
1.32      matthew  1421:               @_,
                   1422:               );
1.165     raeburn  1423:     my ($check4,$check5,$krbarg);
1.80      albertel 1424:     if ($in{'kerb_def_auth'} eq 'krb5') {
                   1425:        $check5 = " checked=\"on\"";
                   1426:     } else {
                   1427:        $check4 = " checked=\"on\"";
                   1428:     }
1.165     raeburn  1429:     $krbarg = $in{'kerb_def_dom'};
                   1430: 
                   1431:     my $krbcheck = "";
                   1432:     if ( grep/^curr_authtype$/,(keys %in) ) {
                   1433:         if ($in{'curr_authtype'} =~ m/^krb/) {
                   1434:             $krbcheck = " checked=\"on\"";
                   1435:             if ( grep/^curr_autharg$/,(keys %in) ) {
                   1436:                 $krbarg = $in{'curr_autharg'};
                   1437:             }
                   1438:         }
                   1439:     }
                   1440: 
1.144     matthew  1441:     my $jscall = "javascript:changed_radio('krb',$in{'formname'});";
                   1442:     my $result .= &mt
                   1443:         ('[_1] Kerberos authenticated with domain [_2] '.
                   1444:          '[_3] Version 4 [_4] Version 5',
                   1445:          '<input type="radio" name="login" value="krb" '.
1.165     raeburn  1446:              'onclick="'.$jscall.'" onchange="'.$jscall.'"'.$krbcheck.' />',
1.144     matthew  1447:          '<input type="text" size="10" name="krbarg" '.
1.165     raeburn  1448:              'value="'.$krbarg.'" '.
1.144     matthew  1449:              'onchange="'.$jscall.'" />',
                   1450:          '<input type="radio" name="krbver" value="4" '.$check4.' />',
                   1451:          '<input type="radio" name="krbver" value="5" '.$check5.' />');
1.32      matthew  1452:     return $result;
                   1453: }
                   1454: 
                   1455: sub authform_internal{  
                   1456:     my %args = (
                   1457:                 formname => 'document.cu',
                   1458:                 kerb_def_dom => 'MSU.EDU',
                   1459:                 @_,
                   1460:                 );
1.165     raeburn  1461: 
                   1462:     my $intcheck = "";
                   1463:     my $intarg = 'value=""';
                   1464:     if ( grep/^curr_authtype$/,(keys %args) ) {
                   1465:         if ($args{'curr_authtype'} eq 'int') {
                   1466:             $intcheck = " checked=\"on\"";
                   1467:             if ( grep/^curr_autharg$/,(keys %args) ) {
                   1468:                 $intarg = "value=\"$args{'curr_autharg'}\"";
                   1469:             }
                   1470:         }
                   1471:     }
                   1472: 
1.144     matthew  1473:     my $jscall = "javascript:changed_radio('int',$args{'formname'});";
                   1474:     my $result.=&mt
                   1475:         ('[_1] Internally authenticated (with initial password [_2])',
1.165     raeburn  1476:          '<input type="radio" name="login" value="int" '.$intcheck.
                   1477:              ' onchange="'.$jscall.'" onclick="'.$jscall.'" />',
                   1478:          '<input type="text" size="10" name="intarg" '.$intarg.
                   1479:              ' onchange="'.$jscall.'" />');
1.32      matthew  1480:     return $result;
                   1481: }
                   1482: 
                   1483: sub authform_local{  
                   1484:     my %in = (
                   1485:               formname => 'document.cu',
                   1486:               kerb_def_dom => 'MSU.EDU',
                   1487:               @_,
                   1488:               );
1.165     raeburn  1489: 
                   1490:     my $loccheck = "";
                   1491:     my $locarg = 'value=""';
                   1492:     if ( grep/^curr_authtype$/,(keys %in) ) {
                   1493:         if ($in{'curr_authtype'} eq 'loc') {
                   1494:             $loccheck = " checked=\"on\"";
                   1495:             if ( grep/^curr_autharg$/,(keys %in) ) {
                   1496:                 $locarg = "value=\"$in{'curr_autharg'}\"";
                   1497:             }
                   1498:         }
                   1499:     }
                   1500: 
1.144     matthew  1501:     my $jscall = "javascript:changed_radio('loc',$in{'formname'});";
1.160     matthew  1502:     my $result.=&mt('[_1] Local Authentication with argument [_2]',
1.165     raeburn  1503:                     '<input type="radio" name="login" value="loc" '.$loccheck.
                   1504:                         ' onchange="'.$jscall.'" onclick="'.$jscall.'" />',
                   1505:                     '<input type="text" size="10" name="locarg" '.$locarg.
                   1506:                         ' onchange="'.$jscall.'" />');
1.32      matthew  1507:     return $result;
                   1508: }
                   1509: 
                   1510: sub authform_filesystem{  
                   1511:     my %in = (
                   1512:               formname => 'document.cu',
                   1513:               kerb_def_dom => 'MSU.EDU',
                   1514:               @_,
                   1515:               );
1.144     matthew  1516:     my $jscall = "javascript:changed_radio('fsys',$in{'formname'});";
                   1517:     my $result.= &mt
                   1518:         ('[_1] Filesystem Authenticated (with initial password [_2])',
                   1519:          '<input type="radio" name="login" value="fsys" '.
                   1520:          'onchange="'.$jscall.'" onclick="'.$jscall.'" />',
                   1521:          '<input type="text" size="10" name="fsysarg" value="" '.
                   1522:                   'onchange="'.$jscall.'" />');
1.32      matthew  1523:     return $result;
                   1524: }
                   1525: 
1.80      albertel 1526: ###############################################################
                   1527: ##    Get Authentication Defaults for Domain                 ##
                   1528: ###############################################################
                   1529: 
                   1530: =pod
                   1531: 
1.112     bowersj2 1532: =head1 Domains and Authentication
                   1533: 
                   1534: Returns default authentication type and an associated argument as
                   1535: listed in file 'domain.tab'.
                   1536: 
                   1537: =over 4
                   1538: 
                   1539: =item * get_auth_defaults
1.80      albertel 1540: 
                   1541: get_auth_defaults($target_domain) returns the default authentication
                   1542: type and an associated argument (initial password or a kerberos domain).
                   1543: These values are stored in lonTabs/domain.tab
                   1544: 
                   1545: ($def_auth, $def_arg) = &get_auth_defaults($target_domain);
                   1546: 
                   1547: If target_domain is not found in domain.tab, returns nothing ('').
                   1548: 
                   1549: =cut
                   1550: 
                   1551: #-------------------------------------------
                   1552: sub get_auth_defaults {
                   1553:     my $domain=shift;
                   1554:     return ($Apache::lonnet::domain_auth_def{$domain},$Apache::lonnet::domain_auth_arg_def{$domain});
                   1555: }
                   1556: ###############################################################
                   1557: ##   End Get Authentication Defaults for Domain              ##
                   1558: ###############################################################
                   1559: 
                   1560: ###############################################################
                   1561: ##    Get Kerberos Defaults for Domain                 ##
                   1562: ###############################################################
                   1563: ##
                   1564: ## Returns default kerberos version and an associated argument
                   1565: ## as listed in file domain.tab. If not listed, provides
                   1566: ## appropriate default domain and kerberos version.
                   1567: ##
                   1568: #-------------------------------------------
                   1569: 
                   1570: =pod
                   1571: 
1.112     bowersj2 1572: =item * get_kerberos_defaults
1.80      albertel 1573: 
                   1574: get_kerberos_defaults($target_domain) returns the default kerberos
                   1575: version and domain. If not found in domain.tabs, it defaults to
                   1576: version 4 and the domain of the server.
                   1577: 
                   1578: ($def_version, $def_krb_domain) = &get_kerberos_defaults($target_domain);
                   1579: 
                   1580: =cut
                   1581: 
                   1582: #-------------------------------------------
                   1583: sub get_kerberos_defaults {
                   1584:     my $domain=shift;
                   1585:     my ($krbdef,$krbdefdom) =
                   1586:         &Apache::loncommon::get_auth_defaults($domain);
                   1587:     unless ($krbdef =~/^krb/ && $krbdefdom) {
                   1588:         $ENV{'SERVER_NAME'}=~/(\w+\.\w+)$/;
                   1589:         my $krbdefdom=$1;
                   1590:         $krbdefdom=~tr/a-z/A-Z/;
                   1591:         $krbdef = "krb4";
                   1592:     }
                   1593:     return ($krbdef,$krbdefdom);
                   1594: }
1.112     bowersj2 1595: 
                   1596: =pod
                   1597: 
                   1598: =back
                   1599: 
                   1600: =cut
1.32      matthew  1601: 
1.46      matthew  1602: ###############################################################
                   1603: ##                Thesaurus Functions                        ##
                   1604: ###############################################################
1.20      www      1605: 
1.46      matthew  1606: =pod
1.20      www      1607: 
1.112     bowersj2 1608: =head1 Thesaurus Functions
                   1609: 
                   1610: =over 4
                   1611: 
                   1612: =item * initialize_keywords
1.46      matthew  1613: 
                   1614: Initializes the package variable %Keywords if it is empty.  Uses the
                   1615: package variable $thesaurus_db_file.
                   1616: 
                   1617: =cut
                   1618: 
                   1619: ###################################################
                   1620: 
                   1621: sub initialize_keywords {
                   1622:     return 1 if (scalar keys(%Keywords));
                   1623:     # If we are here, %Keywords is empty, so fill it up
                   1624:     #   Make sure the file we need exists...
                   1625:     if (! -e $thesaurus_db_file) {
                   1626:         &Apache::lonnet::logthis("Attempt to access $thesaurus_db_file".
                   1627:                                  " failed because it does not exist");
                   1628:         return 0;
                   1629:     }
                   1630:     #   Set up the hash as a database
                   1631:     my %thesaurus_db;
                   1632:     if (! tie(%thesaurus_db,'GDBM_File',
1.53      albertel 1633:               $thesaurus_db_file,&GDBM_READER(),0640)){
1.46      matthew  1634:         &Apache::lonnet::logthis("Could not tie \%thesaurus_db to ".
                   1635:                                  $thesaurus_db_file);
                   1636:         return 0;
                   1637:     } 
                   1638:     #  Get the average number of appearances of a word.
                   1639:     my $avecount = $thesaurus_db{'average.count'};
                   1640:     #  Put keywords (those that appear > average) into %Keywords
                   1641:     while (my ($word,$data)=each (%thesaurus_db)) {
                   1642:         my ($count,undef) = split /:/,$data;
                   1643:         $Keywords{$word}++ if ($count > $avecount);
                   1644:     }
                   1645:     untie %thesaurus_db;
                   1646:     # Remove special values from %Keywords.
                   1647:     foreach ('total.count','average.count') {
                   1648:         delete($Keywords{$_}) if (exists($Keywords{$_}));
                   1649:     }
                   1650:     return 1;
                   1651: }
                   1652: 
                   1653: ###################################################
                   1654: 
                   1655: =pod
                   1656: 
1.112     bowersj2 1657: =item * keyword($word)
1.46      matthew  1658: 
                   1659: Returns true if $word is a keyword.  A keyword is a word that appears more 
                   1660: than the average number of times in the thesaurus database.  Calls 
                   1661: &initialize_keywords
                   1662: 
                   1663: =cut
                   1664: 
                   1665: ###################################################
1.20      www      1666: 
                   1667: sub keyword {
1.46      matthew  1668:     return if (!&initialize_keywords());
                   1669:     my $word=lc(shift());
                   1670:     $word=~s/\W//g;
                   1671:     return exists($Keywords{$word});
1.20      www      1672: }
1.46      matthew  1673: 
                   1674: ###############################################################
                   1675: 
                   1676: =pod 
1.20      www      1677: 
1.112     bowersj2 1678: =item * get_related_words
1.46      matthew  1679: 
1.160     matthew  1680: Look up a word in the thesaurus.  Takes a scalar argument and returns
1.46      matthew  1681: an array of words.  If the keyword is not in the thesaurus, an empty array
                   1682: will be returned.  The order of the words returned is determined by the
                   1683: database which holds them.
                   1684: 
                   1685: Uses global $thesaurus_db_file.
                   1686: 
                   1687: =cut
                   1688: 
                   1689: ###############################################################
                   1690: sub get_related_words {
                   1691:     my $keyword = shift;
                   1692:     my %thesaurus_db;
                   1693:     if (! -e $thesaurus_db_file) {
                   1694:         &Apache::lonnet::logthis("Attempt to access $thesaurus_db_file ".
                   1695:                                  "failed because the file does not exist");
                   1696:         return ();
                   1697:     }
                   1698:     if (! tie(%thesaurus_db,'GDBM_File',
1.53      albertel 1699:               $thesaurus_db_file,&GDBM_READER(),0640)){
1.46      matthew  1700:         return ();
                   1701:     } 
                   1702:     my @Words=();
                   1703:     if (exists($thesaurus_db{$keyword})) {
                   1704:         $_ = $thesaurus_db{$keyword};
                   1705:         (undef,@Words) = split/:/;  # The first element is the number of times
                   1706:                                     # the word appears.  We do not need it now.
                   1707:         for (my $i=0;$i<=$#Words;$i++) {
                   1708:             ($Words[$i],undef)= split/\,/,$Words[$i];
1.20      www      1709:         }
                   1710:     }
1.46      matthew  1711:     untie %thesaurus_db;
                   1712:     return @Words;
1.14      harris41 1713: }
1.46      matthew  1714: 
1.112     bowersj2 1715: =pod
                   1716: 
                   1717: =back
                   1718: 
                   1719: =cut
1.61      www      1720: 
                   1721: # -------------------------------------------------------------- Plaintext name
1.81      albertel 1722: =pod
                   1723: 
1.112     bowersj2 1724: =head1 User Name Functions
                   1725: 
                   1726: =over 4
                   1727: 
                   1728: =item * plainname($uname,$udom)
1.81      albertel 1729: 
1.112     bowersj2 1730: Takes a users logon name and returns it as a string in
                   1731: "first middle last generation" form
1.81      albertel 1732: 
                   1733: =cut
1.61      www      1734: 
1.81      albertel 1735: ###############################################################
1.61      www      1736: sub plainname {
                   1737:     my ($uname,$udom)=@_;
                   1738:     my %names=&Apache::lonnet::get('environment',
                   1739:                     ['firstname','middlename','lastname','generation'],
                   1740: 					 $udom,$uname);
1.62      www      1741:     my $name=$names{'firstname'}.' '.$names{'middlename'}.' '.
1.61      www      1742: 	$names{'lastname'}.' '.$names{'generation'};
1.62      www      1743:     $name=~s/\s+$//;
                   1744:     $name=~s/\s+/ /g;
1.190     albertel 1745:     if ($name !~ /\S/) { $name=$uname.'@'.$udom; }
1.62      www      1746:     return $name;
1.61      www      1747: }
1.66      www      1748: 
                   1749: # -------------------------------------------------------------------- Nickname
1.81      albertel 1750: =pod
                   1751: 
1.112     bowersj2 1752: =item * nickname($uname,$udom)
1.81      albertel 1753: 
                   1754: Gets a users name and returns it as a string as
                   1755: 
                   1756: "&quot;nickname&quot;"
1.66      www      1757: 
1.81      albertel 1758: if the user has a nickname or
                   1759: 
                   1760: "first middle last generation"
                   1761: 
                   1762: if the user does not
                   1763: 
                   1764: =cut
1.66      www      1765: 
                   1766: sub nickname {
                   1767:     my ($uname,$udom)=@_;
                   1768:     my %names=&Apache::lonnet::get('environment',
                   1769:   ['nickname','firstname','middlename','lastname','generation'],$udom,$uname);
1.68      albertel 1770:     my $name=$names{'nickname'};
1.66      www      1771:     if ($name) {
                   1772:        $name='&quot;'.$name.'&quot;'; 
                   1773:     } else {
                   1774:        $name=$names{'firstname'}.' '.$names{'middlename'}.' '.
                   1775: 	     $names{'lastname'}.' '.$names{'generation'};
                   1776:        $name=~s/\s+$//;
                   1777:        $name=~s/\s+/ /g;
                   1778:     }
                   1779:     return $name;
                   1780: }
                   1781: 
1.61      www      1782: 
                   1783: # ------------------------------------------------------------------ Screenname
1.81      albertel 1784: 
                   1785: =pod
                   1786: 
1.112     bowersj2 1787: =item * screenname($uname,$udom)
1.81      albertel 1788: 
                   1789: Gets a users screenname and returns it as a string
                   1790: 
                   1791: =cut
1.61      www      1792: 
                   1793: sub screenname {
                   1794:     my ($uname,$udom)=@_;
                   1795:     my %names=
                   1796:  &Apache::lonnet::get('environment',['screenname'],$udom,$uname);
1.68      albertel 1797:     return $names{'screenname'};
1.62      www      1798: }
                   1799: 
                   1800: # ------------------------------------------------------------- Message Wrapper
                   1801: 
                   1802: sub messagewrapper {
1.200     matthew  1803:     my ($link,$username,$domain)=@_;
1.62      www      1804:     return 
1.200     matthew  1805:         '<a href="/adm/email?compose=individual&'.
                   1806:         'recname='.$username.'&recdom='.$domain.'" '.
                   1807:         'title="'.&mt('Send message').'">'.$link.'</a>';
1.74      www      1808: }
                   1809: # --------------------------------------------------------------- Notes Wrapper
                   1810: 
                   1811: sub noteswrapper {
                   1812:     my ($link,$un,$do)=@_;
                   1813:     return 
                   1814: "<a href='/adm/email?recordftf=retrieve&recname=$un&recdom=$do'>$link</a>";
1.62      www      1815: }
                   1816: # ------------------------------------------------------------- Aboutme Wrapper
                   1817: 
                   1818: sub aboutmewrapper {
1.166     www      1819:     my ($link,$username,$domain,$target)=@_;
1.205     www      1820:     return '<a href="/adm/'.$domain.'/'.$username.'/aboutme"'.
1.200     matthew  1821: 	($target?' target="$target"':'').' title="'.&mt('View this users personal page').'">'.$link.'</a>';
1.62      www      1822: }
                   1823: 
                   1824: # ------------------------------------------------------------ Syllabus Wrapper
                   1825: 
                   1826: 
                   1827: sub syllabuswrapper {
1.109     matthew  1828:     my ($linktext,$coursedir,$domain,$fontcolor)=@_;
                   1829:     if ($fontcolor) { 
                   1830:         $linktext='<font color="'.$fontcolor.'">'.$linktext.'</font>'; 
                   1831:     }
1.208   ! matthew  1832:     return qq{<a href="/public/$domain/$coursedir/syllabus">$linktext</a>};
1.61      www      1833: }
1.14      harris41 1834: 
1.208   ! matthew  1835: sub track_student_link {
        !          1836:     my ($linktext,$sname,$sdom,$target) = @_;
        !          1837:     my $link ="/adm/trackstudent";
        !          1838:     my $title = 'View recent activity';
        !          1839:     if (defined($sname) && $sname !~ /^\s*$/ &&
        !          1840:         defined($sdom)  && $sdom  !~ /^\s*$/) {
        !          1841:         $link .= "?selected_student=$sname:$sdom";
        !          1842:         $title .= ' of this student';
        !          1843:     }
        !          1844:     if (defined($target) && $target !~ /^\s*$/) {
        !          1845:         $target = qq{target="$target"};
        !          1846:     } else {
        !          1847:         $target = '';
        !          1848:     }
        !          1849:     return qq{<a href="$link" title="$title" $target>$linktext</a>};
        !          1850: }
        !          1851: 
        !          1852: 
        !          1853: 
1.112     bowersj2 1854: =pod
                   1855: 
                   1856: =back
                   1857: 
                   1858: =head1 Access .tab File Data
                   1859: 
                   1860: =over 4
                   1861: 
                   1862: =item * languageids() 
                   1863: 
                   1864: returns list of all language ids
                   1865: 
                   1866: =cut
                   1867: 
1.14      harris41 1868: sub languageids {
1.16      harris41 1869:     return sort(keys(%language));
1.14      harris41 1870: }
                   1871: 
1.112     bowersj2 1872: =pod
                   1873: 
                   1874: =item * languagedescription() 
                   1875: 
                   1876: returns description of a specified language id
                   1877: 
                   1878: =cut
                   1879: 
1.14      harris41 1880: sub languagedescription {
1.125     www      1881:     my $code=shift;
                   1882:     return  ($supported_language{$code}?'* ':'').
                   1883:             $language{$code}.
1.126     www      1884: 	    ($supported_language{$code}?' ('.&mt('interface available').')':'');
1.145     www      1885: }
                   1886: 
                   1887: sub plainlanguagedescription {
                   1888:     my $code=shift;
                   1889:     return $language{$code};
                   1890: }
                   1891: 
                   1892: sub supportedlanguagecode {
                   1893:     my $code=shift;
                   1894:     return $supported_language{$code};
1.97      www      1895: }
                   1896: 
1.112     bowersj2 1897: =pod
                   1898: 
                   1899: =item * copyrightids() 
                   1900: 
                   1901: returns list of all copyrights
                   1902: 
                   1903: =cut
                   1904: 
                   1905: sub copyrightids {
                   1906:     return sort(keys(%cprtag));
                   1907: }
                   1908: 
                   1909: =pod
                   1910: 
                   1911: =item * copyrightdescription() 
                   1912: 
                   1913: returns description of a specified copyright id
                   1914: 
                   1915: =cut
                   1916: 
                   1917: sub copyrightdescription {
1.166     www      1918:     return &mt($cprtag{shift(@_)});
1.112     bowersj2 1919: }
1.197     matthew  1920: 
                   1921: =pod
                   1922: 
1.192     taceyjo1 1923: =item * source_copyrightids() 
                   1924: 
                   1925: returns list of all source copyrights
                   1926: 
                   1927: =cut
                   1928: 
                   1929: sub source_copyrightids {
                   1930:     return sort(keys(%scprtag));
                   1931: }
                   1932: 
                   1933: =pod
                   1934: 
                   1935: =item * source_copyrightdescription() 
                   1936: 
                   1937: returns description of a specified source copyright id
                   1938: 
                   1939: =cut
                   1940: 
                   1941: sub source_copyrightdescription {
                   1942:     return &mt($scprtag{shift(@_)});
                   1943: }
1.112     bowersj2 1944: 
                   1945: =pod
                   1946: 
                   1947: =item * filecategories() 
                   1948: 
                   1949: returns list of all file categories
                   1950: 
                   1951: =cut
                   1952: 
                   1953: sub filecategories {
                   1954:     return sort(keys(%category_extensions));
                   1955: }
                   1956: 
                   1957: =pod
                   1958: 
                   1959: =item * filecategorytypes() 
                   1960: 
                   1961: returns list of file types belonging to a given file
                   1962: category
                   1963: 
                   1964: =cut
                   1965: 
                   1966: sub filecategorytypes {
                   1967:     return @{$category_extensions{lc($_[0])}};
                   1968: }
                   1969: 
                   1970: =pod
                   1971: 
                   1972: =item * fileembstyle() 
                   1973: 
                   1974: returns embedding style for a specified file type
                   1975: 
                   1976: =cut
                   1977: 
                   1978: sub fileembstyle {
                   1979:     return $fe{lc(shift(@_))};
1.169     www      1980: }
                   1981: 
                   1982: 
                   1983: sub filecategoryselect {
                   1984:     my ($name,$value)=@_;
1.189     matthew  1985:     return &select_form($value,$name,
1.169     www      1986: 			'' => &mt('Any category'),
                   1987: 			map { $_,$_ } sort(keys(%category_extensions)));
1.112     bowersj2 1988: }
                   1989: 
                   1990: =pod
                   1991: 
                   1992: =item * filedescription() 
                   1993: 
                   1994: returns description for a specified file type
                   1995: 
                   1996: =cut
                   1997: 
                   1998: sub filedescription {
1.188     matthew  1999:     my $file_description = $fd{lc(shift())};
                   2000:     $file_description =~ s:([\[\]]):~$1:g;
                   2001:     return &mt($file_description);
1.112     bowersj2 2002: }
                   2003: 
                   2004: =pod
                   2005: 
                   2006: =item * filedescriptionex() 
                   2007: 
                   2008: returns description for a specified file type with
                   2009: extra formatting
                   2010: 
                   2011: =cut
                   2012: 
                   2013: sub filedescriptionex {
                   2014:     my $ex=shift;
1.188     matthew  2015:     my $file_description = $fd{lc($ex)};
                   2016:     $file_description =~ s:([\[\]]):~$1:g;
                   2017:     return '.'.$ex.' '.&mt($file_description);
1.112     bowersj2 2018: }
                   2019: 
                   2020: # End of .tab access
                   2021: =pod
                   2022: 
                   2023: =back
                   2024: 
                   2025: =cut
                   2026: 
                   2027: # ------------------------------------------------------------------ File Types
                   2028: sub fileextensions {
                   2029:     return sort(keys(%fe));
                   2030: }
                   2031: 
1.97      www      2032: # ----------------------------------------------------------- Display Languages
                   2033: # returns a hash with all desired display languages
                   2034: #
                   2035: 
                   2036: sub display_languages {
                   2037:     my %languages=();
1.118     www      2038:     foreach (&preferred_languages()) {
                   2039: 	$languages{$_}=1;
1.97      www      2040:     }
                   2041:     &get_unprocessed_cgi($ENV{'QUERY_STRING'},['displaylanguage']);
                   2042:     if ($ENV{'form.displaylanguage'}) {
                   2043: 	foreach (split(/\s*(\,|\;|\:)\s*/,$ENV{'form.displaylanguage'})) {
                   2044: 	    $languages{$_}=1;
                   2045:         }
                   2046:     }
                   2047:     return %languages;
1.14      harris41 2048: }
                   2049: 
1.117     www      2050: sub preferred_languages {
                   2051:     my @languages=();
                   2052:     if ($ENV{'course.'.$ENV{'request.course.id'}.'.languages'}) {
                   2053: 	@languages=(@languages,split(/\s*(\,|\;|\:)\s*/,
                   2054: 	         $ENV{'course.'.$ENV{'request.course.id'}.'.languages'}));
1.177     www      2055:     }
                   2056:     if ($ENV{'environment.languages'}) {
                   2057: 	@languages=split(/\s*(\,|\;|\:)\s*/,$ENV{'environment.languages'});
1.118     www      2058:     }
1.162     www      2059:     my $browser=(split(/\;/,$ENV{'HTTP_ACCEPT_LANGUAGE'}))[0];
                   2060:     if ($browser) {
                   2061: 	@languages=(@languages,split(/\s*(\,|\;|\:)\s*/,$browser));
                   2062:     }
1.118     www      2063:     if ($Apache::lonnet::domain_lang_def{$ENV{'user.domain'}}) {
                   2064: 	@languages=(@languages,
                   2065: 		$Apache::lonnet::domain_lang_def{$ENV{'user.domain'}});
                   2066:     }
                   2067:     if ($Apache::lonnet::domain_lang_def{$ENV{'request.role.domain'}}) {
                   2068: 	@languages=(@languages,
                   2069: 		$Apache::lonnet::domain_lang_def{$ENV{'request.role.domain'}});
                   2070:     }
                   2071:     if ($Apache::lonnet::domain_lang_def{
                   2072: 	                          $Apache::lonnet::perlvar{'lonDefDomain'}}) {
                   2073: 	@languages=(@languages,
                   2074: 		$Apache::lonnet::domain_lang_def{
                   2075:                                   $Apache::lonnet::perlvar{'lonDefDomain'}});
                   2076:     }
                   2077: # turn "en-ca" into "en-ca,en"
                   2078:     my @genlanguages;
                   2079:     foreach (@languages) {
                   2080: 	unless ($_=~/\w/) { next; }
                   2081: 	push (@genlanguages,$_);
                   2082: 	if ($_=~/(\-|\_)/) {
                   2083: 	    push (@genlanguages,(split(/(\-|\_)/,$_))[0]);
                   2084: 	}
                   2085:     }
                   2086:     return @genlanguages;
1.117     www      2087: }
                   2088: 
1.112     bowersj2 2089: ###############################################################
                   2090: ##               Student Answer Attempts                     ##
                   2091: ###############################################################
                   2092: 
                   2093: =pod
                   2094: 
                   2095: =head1 Alternate Problem Views
                   2096: 
                   2097: =over 4
                   2098: 
                   2099: =item * get_previous_attempt($symb, $username, $domain, $course,
                   2100:     $getattempt, $regexp, $gradesub)
                   2101: 
                   2102: Return string with previous attempt on problem. Arguments:
                   2103: 
                   2104: =over 4
                   2105: 
                   2106: =item * $symb: Problem, including path
                   2107: 
                   2108: =item * $username: username of the desired student
                   2109: 
                   2110: =item * $domain: domain of the desired student
1.14      harris41 2111: 
1.112     bowersj2 2112: =item * $course: Course ID
1.14      harris41 2113: 
1.112     bowersj2 2114: =item * $getattempt: Leave blank for all attempts, otherwise put
                   2115:     something
1.14      harris41 2116: 
1.112     bowersj2 2117: =item * $regexp: if string matches this regexp, the string will be
                   2118:     sent to $gradesub
1.14      harris41 2119: 
1.112     bowersj2 2120: =item * $gradesub: routine that processes the string if it matches $regexp
1.14      harris41 2121: 
1.112     bowersj2 2122: =back
1.14      harris41 2123: 
1.112     bowersj2 2124: The output string is a table containing all desired attempts, if any.
1.16      harris41 2125: 
1.112     bowersj2 2126: =cut
1.1       albertel 2127: 
                   2128: sub get_previous_attempt {
1.43      ng       2129:   my ($symb,$username,$domain,$course,$getattempt,$regexp,$gradesub)=@_;
1.1       albertel 2130:   my $prevattempts='';
1.43      ng       2131:   no strict 'refs';
1.1       albertel 2132:   if ($symb) {
1.3       albertel 2133:     my (%returnhash)=
                   2134:       &Apache::lonnet::restore($symb,$course,$domain,$username);
1.1       albertel 2135:     if ($returnhash{'version'}) {
                   2136:       my %lasthash=();
                   2137:       my $version;
                   2138:       for ($version=1;$version<=$returnhash{'version'};$version++) {
1.19      harris41 2139:         foreach (sort(split(/\:/,$returnhash{$version.':keys'}))) {
1.1       albertel 2140: 	  $lasthash{$_}=$returnhash{$version.':'.$_};
1.19      harris41 2141:         }
1.1       albertel 2142:       }
1.43      ng       2143:       $prevattempts='<table border="0" width="100%"><tr><td bgcolor="#777777">';
1.40      ng       2144:       $prevattempts.='<table border="0" width="100%"><tr bgcolor="#e6ffff"><td>History</td>';
1.16      harris41 2145:       foreach (sort(keys %lasthash)) {
1.31      albertel 2146: 	my ($ign,@parts) = split(/\./,$_);
1.41      ng       2147: 	if ($#parts > 0) {
1.31      albertel 2148: 	  my $data=$parts[-1];
                   2149: 	  pop(@parts);
1.40      ng       2150: 	  $prevattempts.='<td>Part '.join('.',@parts).'<br />'.$data.'&nbsp;</td>';
1.31      albertel 2151: 	} else {
1.41      ng       2152: 	  if ($#parts == 0) {
                   2153: 	    $prevattempts.='<th>'.$parts[0].'</th>';
                   2154: 	  } else {
                   2155: 	    $prevattempts.='<th>'.$ign.'</th>';
                   2156: 	  }
1.31      albertel 2157: 	}
1.16      harris41 2158:       }
1.40      ng       2159:       if ($getattempt eq '') {
                   2160: 	for ($version=1;$version<=$returnhash{'version'};$version++) {
                   2161: 	  $prevattempts.='</tr><tr bgcolor="#ffffe6"><td>Transaction '.$version.'</td>';
                   2162: 	    foreach (sort(keys %lasthash)) {
                   2163: 	       my $value;
                   2164: 	       if ($_ =~ /timestamp/) {
                   2165: 		  $value=scalar(localtime($returnhash{$version.':'.$_}));
                   2166: 	       } else {
                   2167: 		  $value=$returnhash{$version.':'.$_};
                   2168: 	       }
1.142     albertel 2169: 	       $prevattempts.='<td>'.&Apache::lonnet::unescape($value).'&nbsp;</td>';   
1.40      ng       2170: 	    }
                   2171: 	 }
1.1       albertel 2172:       }
1.40      ng       2173:       $prevattempts.='</tr><tr bgcolor="#ffffe6"><td>Current</td>';
1.16      harris41 2174:       foreach (sort(keys %lasthash)) {
1.5       albertel 2175: 	my $value;
                   2176: 	if ($_ =~ /timestamp/) {
                   2177: 	  $value=scalar(localtime($lasthash{$_}));
                   2178: 	} else {
                   2179: 	  $value=$lasthash{$_};
                   2180: 	}
1.142     albertel 2181: 	$value=&Apache::lonnet::unescape($value);
1.49      ng       2182: 	if ($_ =~/$regexp$/ && (defined &$gradesub)) {$value = &$gradesub($value)}
1.40      ng       2183: 	$prevattempts.='<td>'.$value.'&nbsp;</td>';
1.16      harris41 2184:       }
1.40      ng       2185:       $prevattempts.='</tr></table></td></tr></table>';
1.1       albertel 2186:     } else {
                   2187:       $prevattempts='Nothing submitted - no attempts.';
                   2188:     }
                   2189:   } else {
                   2190:     $prevattempts='No data.';
                   2191:   }
1.10      albertel 2192: }
                   2193: 
1.107     albertel 2194: sub relative_to_absolute {
                   2195:     my ($url,$output)=@_;
                   2196:     my $parser=HTML::TokeParser->new(\$output);
                   2197:     my $token;
                   2198:     my $thisdir=$url;
                   2199:     my @rlinks=();
                   2200:     while ($token=$parser->get_token) {
                   2201: 	if ($token->[0] eq 'S') {
                   2202: 	    if ($token->[1] eq 'a') {
                   2203: 		if ($token->[2]->{'href'}) {
                   2204: 		    $rlinks[$#rlinks+1]=$token->[2]->{'href'};
                   2205: 		}
                   2206: 	    } elsif ($token->[1] eq 'img' || $token->[1] eq 'embed' ) {
                   2207: 		$rlinks[$#rlinks+1]=$token->[2]->{'src'};
                   2208: 	    } elsif ($token->[1] eq 'base') {
                   2209: 		$thisdir=$token->[2]->{'href'};
                   2210: 	    }
                   2211: 	}
                   2212:     }
                   2213:     $thisdir=~s-/[^/]*$--;
                   2214:     foreach (@rlinks) {
                   2215: 	unless (($_=~/^http:\/\//i) ||
                   2216: 		($_=~/^\//) ||
                   2217: 		($_=~/^javascript:/i) ||
                   2218: 		($_=~/^mailto:/i) ||
                   2219: 		($_=~/^\#/)) {
                   2220: 	    my $newlocation=&Apache::lonnet::hreflocation($thisdir,$_);
                   2221: 	    $output=~s/(\"|\'|\=\s*)$_(\"|\'|\s|\>)/$1$newlocation$2/;
                   2222: 	}
                   2223:     }
                   2224: # -------------------------------------------------- Deal with Applet codebases
                   2225:     $output=~s/(\<applet[^\>]+)(codebase\=[^\S\>]+)*([^\>]*)\>/$1.($2?$2:' codebase="'.$thisdir.'"').$3.'>'/gei;
                   2226:     return $output;
                   2227: }
                   2228: 
1.112     bowersj2 2229: =pod
                   2230: 
                   2231: =item * get_student_view
                   2232: 
                   2233: show a snapshot of what student was looking at
                   2234: 
                   2235: =cut
                   2236: 
1.10      albertel 2237: sub get_student_view {
1.186     albertel 2238:   my ($symb,$username,$domain,$courseid,$target,$moreenv) = @_;
1.114     www      2239:   my ($map,$id,$feedurl) = &Apache::lonnet::decode_symb($symb);
1.186     albertel 2240:   my (%form);
1.10      albertel 2241:   my @elements=('symb','courseid','domain','username');
                   2242:   foreach my $element (@elements) {
1.186     albertel 2243:       $form{'grade_'.$element}=eval '$'.$element #'
1.10      albertel 2244:   }
1.186     albertel 2245:   if (defined($moreenv)) {
                   2246:       %form=(%form,%{$moreenv});
                   2247:   }
                   2248:   if ($target eq 'tex') {$form{'grade_target'} = 'tex';}
1.107     albertel 2249:   $feedurl=&Apache::lonnet::clutter($feedurl);
1.186     albertel 2250:   my $userview=&Apache::lonnet::ssi_body($feedurl,%form);
1.11      albertel 2251:   $userview=~s/\<body[^\>]*\>//gi;
                   2252:   $userview=~s/\<\/body\>//gi;
                   2253:   $userview=~s/\<html\>//gi;
                   2254:   $userview=~s/\<\/html\>//gi;
                   2255:   $userview=~s/\<head\>//gi;
                   2256:   $userview=~s/\<\/head\>//gi;
                   2257:   $userview=~s/action\s*\=/would_be_action\=/gi;
1.107     albertel 2258:   $userview=&relative_to_absolute($feedurl,$userview);
1.11      albertel 2259:   return $userview;
                   2260: }
                   2261: 
1.112     bowersj2 2262: =pod
                   2263: 
                   2264: =item * get_student_answers() 
                   2265: 
                   2266: show a snapshot of how student was answering problem
                   2267: 
                   2268: =cut
                   2269: 
1.11      albertel 2270: sub get_student_answers {
1.100     sakharuk 2271:   my ($symb,$username,$domain,$courseid,%form) = @_;
1.114     www      2272:   my ($map,$id,$feedurl) = &Apache::lonnet::decode_symb($symb);
1.186     albertel 2273:   my (%moreenv);
1.11      albertel 2274:   my @elements=('symb','courseid','domain','username');
                   2275:   foreach my $element (@elements) {
1.186     albertel 2276:     $moreenv{'grade_'.$element}=eval '$'.$element #'
1.10      albertel 2277:   }
1.186     albertel 2278:   $moreenv{'grade_target'}='answer';
                   2279:   %moreenv=(%form,%moreenv);
                   2280:   my $userview=&Apache::lonnet::ssi('/res/'.$feedurl,%moreenv);
1.10      albertel 2281:   return $userview;
1.1       albertel 2282: }
1.116     albertel 2283: 
                   2284: =pod
                   2285: 
                   2286: =item * &submlink()
                   2287: 
                   2288: Inputs: $text $uname $udom $symb
                   2289: 
                   2290: Returns: A link to grades.pm such as to see the SUBM view of a student
                   2291: 
                   2292: =cut
                   2293: 
                   2294: ###############################################
                   2295: sub submlink {
                   2296:     my ($text,$uname,$udom,$symb)=@_;
                   2297:     if (!($uname && $udom)) {
                   2298: 	(my $cursymb, my $courseid,$udom,$uname)=
                   2299: 	    &Apache::lonxml::whichuser($symb);
                   2300: 	if (!$symb) { $symb=$cursymb; }
                   2301:     }
                   2302:     if (!$symb) { $symb=&symbread(); }
                   2303:     return '<a href="/adm/grades?symb='.$symb.'&student='.$uname.
                   2304: 	'&userdom='.$udom.'&command=submission">'.$text.'</a>';
                   2305: }
                   2306: ##############################################
1.37      matthew  2307: 
1.112     bowersj2 2308: =pod
                   2309: 
                   2310: =back
                   2311: 
                   2312: =cut
                   2313: 
1.37      matthew  2314: ###############################################
1.51      www      2315: 
                   2316: 
                   2317: sub timehash {
                   2318:     my @ltime=localtime(shift);
                   2319:     return ( 'seconds' => $ltime[0],
                   2320:              'minutes' => $ltime[1],
                   2321:              'hours'   => $ltime[2],
                   2322:              'day'     => $ltime[3],
                   2323:              'month'   => $ltime[4]+1,
                   2324:              'year'    => $ltime[5]+1900,
                   2325:              'weekday' => $ltime[6],
                   2326:              'dayyear' => $ltime[7]+1,
                   2327:              'dlsav'   => $ltime[8] );
                   2328: }
                   2329: 
                   2330: sub maketime {
                   2331:     my %th=@_;
                   2332:     return POSIX::mktime(
                   2333:         ($th{'seconds'},$th{'minutes'},$th{'hours'},
                   2334:          $th{'day'},$th{'month'}-1,$th{'year'}-1900,0,0,$th{'dlsav'}));
1.70      www      2335: }
                   2336: 
                   2337: #########################################
1.51      www      2338: 
                   2339: sub findallcourses {
                   2340:     my %courses=();
                   2341:     my $now=time;
                   2342:     foreach (keys %ENV) {
                   2343: 	if ($_=~/^user\.role\.\w+\.\/(\w+)\/(\w+)/) {
                   2344: 	    my ($starttime,$endtime)=$ENV{$_};
                   2345:             my $active=1;
                   2346:             if ($starttime) {
                   2347: 		if ($now<$starttime) { $active=0; }
                   2348:             }
                   2349:             if ($endtime) {
                   2350:                 if ($now>$endtime) { $active=0; }
                   2351:             }
                   2352:             if ($active) { $courses{$1.'_'.$2}=1; }
                   2353:         }
                   2354:     }
                   2355:     return keys %courses;
                   2356: }
1.37      matthew  2357: 
1.54      www      2358: ###############################################
1.60      matthew  2359: ###############################################
                   2360: 
                   2361: =pod
                   2362: 
1.112     bowersj2 2363: =head1 Domain Template Functions
                   2364: 
                   2365: =over 4
                   2366: 
                   2367: =item * &determinedomain()
1.60      matthew  2368: 
                   2369: Inputs: $domain (usually will be undef)
                   2370: 
1.63      www      2371: Returns: Determines which domain should be used for designs
1.60      matthew  2372: 
                   2373: =cut
1.54      www      2374: 
1.60      matthew  2375: ###############################################
1.63      www      2376: sub determinedomain {
                   2377:     my $domain=shift;
                   2378:    if (! $domain) {
1.60      matthew  2379:         # Determine domain if we have not been given one
                   2380:         $domain = $Apache::lonnet::perlvar{'lonDefDomain'};
                   2381:         if ($ENV{'user.domain'}) { $domain=$ENV{'user.domain'}; }
                   2382:         if ($ENV{'request.role.domain'}) { 
                   2383:             $domain=$ENV{'request.role.domain'}; 
                   2384:         }
                   2385:     }
1.63      www      2386:     return $domain;
                   2387: }
                   2388: ###############################################
                   2389: =pod
                   2390: 
1.112     bowersj2 2391: =item * &domainlogo()
1.63      www      2392: 
                   2393: Inputs: $domain (usually will be undef)
                   2394: 
                   2395: Returns: A link to a domain logo, if the domain logo exists.
                   2396: If the domain logo does not exist, a description of the domain.
                   2397: 
                   2398: =cut
1.112     bowersj2 2399: 
1.63      www      2400: ###############################################
                   2401: sub domainlogo {
                   2402:     my $domain = &determinedomain(shift);    
                   2403:      # See if there is a logo
1.59      www      2404:     if (-e '/home/httpd/html/adm/lonDomLogos/'.$domain.'.gif') {
1.83      albertel 2405: 	my $lonhttpdPort=$Apache::lonnet::perlvar{'lonhttpdPort'};
                   2406: 	if (!defined($lonhttpdPort)) { $lonhttpdPort='8080'; }
                   2407:         return '<img src="http://'.$ENV{'HTTP_HOST'}.':'.$lonhttpdPort.
1.150     matthew  2408: 	    '/adm/lonDomLogos/'.$domain.'.gif" alt="'.$domain.'" />';
1.60      matthew  2409:     } elsif(exists($Apache::lonnet::domaindescription{$domain})) {
                   2410:         return $Apache::lonnet::domaindescription{$domain};
1.59      www      2411:     } else {
1.60      matthew  2412:         return '';
1.59      www      2413:     }
                   2414: }
1.63      www      2415: ##############################################
                   2416: 
                   2417: =pod
                   2418: 
1.112     bowersj2 2419: =item * &designparm()
1.63      www      2420: 
                   2421: Inputs: $which parameter; $domain (usually will be undef)
                   2422: 
                   2423: Returns: value of designparamter $which
                   2424: 
                   2425: =cut
1.112     bowersj2 2426: 
1.63      www      2427: ##############################################
                   2428: sub designparm {
                   2429:     my ($which,$domain)=@_;
1.110     www      2430:     if ($ENV{'browser.blackwhite'} eq 'on') {
                   2431: 	if ($which=~/\.(font|alink|vlink|link)$/) {
                   2432: 	    return '#000000';
                   2433: 	}
                   2434: 	if ($which=~/\.(pgbg|sidebg)$/) {
                   2435: 	    return '#FFFFFF';
                   2436: 	}
                   2437: 	if ($which=~/\.tabbg$/) {
                   2438: 	    return '#CCCCCC';
                   2439: 	}
                   2440:     }
1.96      www      2441:     if ($ENV{'environment.color.'.$which}) {
                   2442: 	return $ENV{'environment.color.'.$which};
                   2443:     }
1.63      www      2444:     $domain=&determinedomain($domain);
                   2445:     if ($designhash{$domain.'.'.$which}) {
                   2446: 	return $designhash{$domain.'.'.$which};
                   2447:     } else {
                   2448:         return $designhash{'default.'.$which};
                   2449:     }
                   2450: }
1.59      www      2451: 
1.60      matthew  2452: ###############################################
                   2453: ###############################################
                   2454: 
                   2455: =pod
                   2456: 
1.112     bowersj2 2457: =back
                   2458: 
                   2459: =head1 HTTP Helpers
                   2460: 
                   2461: =over 4
                   2462: 
                   2463: =item * &bodytag()
1.60      matthew  2464: 
                   2465: Returns a uniform header for LON-CAPA web pages.
                   2466: 
                   2467: Inputs: 
                   2468: 
1.112     bowersj2 2469: =over 4
                   2470: 
                   2471: =item * $title, A title to be displayed on the page.
                   2472: 
                   2473: =item * $function, the current role (can be undef).
                   2474: 
                   2475: =item * $addentries, extra parameters for the <body> tag.
                   2476: 
                   2477: =item * $bodyonly, if defined, only return the <body> tag.
                   2478: 
                   2479: =item * $domain, if defined, force a given domain.
                   2480: 
                   2481: =item * $forcereg, if page should register as content page (relevant for 
1.86      www      2482:             text interface only)
1.60      matthew  2483: 
1.112     bowersj2 2484: =back
                   2485: 
1.60      matthew  2486: Returns: A uniform header for LON-CAPA web pages.  
                   2487: If $bodyonly is nonzero, a string containing a <body> tag will be returned.
                   2488: If $bodyonly is undef or zero, an html string containing a <body> tag and 
                   2489: other decorations will be returned.
                   2490: 
                   2491: =cut
                   2492: 
1.54      www      2493: sub bodytag {
1.86      www      2494:     my ($title,$function,$addentries,$bodyonly,$domain,$forcereg)=@_;
1.117     www      2495:     $title=&mt($title);
1.183     matthew  2496:     $function = &get_users_function() if (!$function);
1.63      www      2497:     my $img=&designparm($function.'.img',$domain);
                   2498:     my $pgbg=&designparm($function.'.pgbg',$domain);
                   2499:     my $tabbg=&designparm($function.'.tabbg',$domain);
                   2500:     my $font=&designparm($function.'.font',$domain);
                   2501:     my $link=&designparm($function.'.link',$domain);
                   2502:     my $alink=&designparm($function.'.alink',$domain);
                   2503:     my $vlink=&designparm($function.'.vlink',$domain);
                   2504:     my $sidebg=&designparm($function.'.sidebg',$domain);
1.110     www      2505: # Accessibility font enhance
                   2506:     unless ($addentries) { $addentries=''; }
1.146     www      2507:     my $addstyle='';
1.110     www      2508:     if ($ENV{'browser.fontenhance'} eq 'on') {
1.146     www      2509: 	$addstyle=' font-size: x-large;';
1.110     www      2510:     }
1.63      www      2511:  # role and realm
1.55      www      2512:     my ($role,$realm)
                   2513:        =&Apache::lonnet::plaintext((split(/\./,$ENV{'request.role'}))[0]);
                   2514: # realm
1.54      www      2515:     if ($ENV{'request.course.id'}) {
1.55      www      2516: 	$realm=
                   2517:          $ENV{'course.'.$ENV{'request.course.id'}.'.description'};
1.54      www      2518:     }
1.55      www      2519:     unless ($realm) { $realm='&nbsp;'; }
                   2520: # Set messages
1.60      matthew  2521:     my $messages=&domainlogo($domain);
1.101     www      2522: # Port for miniserver
1.83      albertel 2523:     my $lonhttpdPort=$Apache::lonnet::perlvar{'lonhttpdPort'};
                   2524:     if (!defined($lonhttpdPort)) { $lonhttpdPort='8080'; }
1.101     www      2525: # construct main body tag
1.60      matthew  2526:     my $bodytag = <<END;
1.146     www      2527: <style>
1.147     www      2528: h1, h2, h3, th { font-family: Arial, Helvetica, sans-serif }
1.146     www      2529: a:focus { color: red; background: yellow } 
                   2530: </style>
1.54      www      2531: <body bgcolor="$pgbg" text="$font" alink="$alink" vlink="$vlink" link="$link"
1.151     www      2532: style="margin-top: 0px;$addstyle" $addentries>
1.60      matthew  2533: END
1.94      www      2534:     my $upperleft='<img src="http://'.$ENV{'HTTP_HOST'}.':'.
1.150     matthew  2535:                    $lonhttpdPort.$img.'" alt="'.$function.'" />';
1.60      matthew  2536:     if ($bodyonly) {
                   2537:         return $bodytag;
1.79      www      2538:     } elsif ($ENV{'browser.interface'} eq 'textual') {
1.95      www      2539: # Accessibility
1.93      www      2540:         return $bodytag.&Apache::lonmenu::menubuttons($forcereg,'web',
                   2541:                                                       $forcereg).
                   2542:                '<h1>LON-CAPA: '.$title.'</h1>';
                   2543:     } elsif ($ENV{'environment.remote'} eq 'off') {
1.95      www      2544: # No Remote
1.206     albertel 2545: 	my $roleinfo=(<<ENDROLE);
                   2546: <td bgcolor="$tabbg" align="right">
                   2547: <p>
                   2548: <font size="2" face="Arial, Helvetica, sans-serif">
                   2549:     $ENV{'environment.firstname'}
                   2550:     $ENV{'environment.middlename'}
                   2551:     $ENV{'environment.lastname'}
                   2552:     $ENV{'environment.generation'}
                   2553:     </font>&nbsp;
                   2554: <br />
                   2555: <font size="2" face="Arial, Helvetica, sans-serif">$role</font>&nbsp;
                   2556: <br />
                   2557: <font size="2" face="Arial, Helvetica, sans-serif">$realm</font>&nbsp;
                   2558: </p>
                   2559: </td>
                   2560: ENDROLE
1.95      www      2561:         return $bodytag.&Apache::lonmenu::menubuttons($forcereg,'web',
                   2562:                                                       $forcereg).
1.206     albertel 2563:       '<table bgcolor="'.$pgbg.'" width="100%" border="0" cellspacing="3" cellpadding="3"><tr><td rowspan="3" bgcolor="'.$tabbg.'"><font face="Arial, Helvetica, sans-serif" size="+3" color="'.$font.'"><b>'.$title.
                   2564: '</b></font></td>'.$roleinfo.'</tr></table>';
1.94      www      2565:     }
1.95      www      2566: 
1.93      www      2567: #
1.95      www      2568: # Top frame rendering, Remote is up
1.93      www      2569: #
1.94      www      2570:     return(<<ENDBODY);
1.60      matthew  2571: $bodytag
1.55      www      2572: <table width="100%" cellspacing="0" border="0" cellpadding="0">
1.95      www      2573: <tr><td bgcolor="$sidebg">
1.94      www      2574: $upperleft</td>
1.95      www      2575: <td bgcolor="$sidebg" align="right">$messages&nbsp;</td>
1.55      www      2576: </tr>
1.54      www      2577: <tr>
1.55      www      2578: <td rowspan="3" bgcolor="$tabbg">
1.146     www      2579: &nbsp;<font size="5" face="Arial, Helvetica, sans-serif"><b>$title</b></font>
                   2580: <td bgcolor="$tabbg" align="right">
                   2581: <font size="2" face="Arial, Helvetica, sans-serif">
1.54      www      2582:     $ENV{'environment.firstname'}
                   2583:     $ENV{'environment.middlename'}
                   2584:     $ENV{'environment.lastname'}
                   2585:     $ENV{'environment.generation'}
1.55      www      2586:     </font>&nbsp;
1.54      www      2587: </td>
                   2588: </tr>
                   2589: <tr><td bgcolor="$tabbg" align="right">
1.146     www      2590: <font size="2" face="Arial, Helvetica, sans-serif">$role</font>&nbsp;
1.54      www      2591: </td></tr>
1.55      www      2592: <tr>
1.148     www      2593: <td bgcolor="$tabbg" align="right"><font size="2" face="Arial, Helvetica, sans-serif">$realm</font>&nbsp;</td></tr>
1.202     albertel 2594: </table><br />
1.54      www      2595: ENDBODY
1.182     matthew  2596: }
                   2597: 
                   2598: ###############################################
                   2599: 
                   2600: =pod
                   2601: 
                   2602: =item get_users_function
                   2603: 
                   2604: Used by &bodytag to determine the current users primary role.
                   2605: Returns either 'student','coordinator','admin', or 'author'.
                   2606: 
                   2607: =cut
                   2608: 
                   2609: ###############################################
                   2610: sub get_users_function {
                   2611:     my $function = 'student';
                   2612:     if ($ENV{'request.role'}=~/^(cc|in|ta|ep)/) {
                   2613:         $function='coordinator';
                   2614:     }
                   2615:     if ($ENV{'request.role'}=~/^(su|dc|ad|li)/) {
                   2616:         $function='admin';
                   2617:     }
                   2618:     if (($ENV{'request.role'}=~/^(au|ca)/) ||
                   2619:         ($ENV{'REQUEST_URI'}=~/^(\/priv|\~)/)) {
                   2620:         $function='author';
                   2621:     }
                   2622:     return $function;
1.54      www      2623: }
1.99      www      2624: 
                   2625: ###############################################
                   2626: 
                   2627: sub get_posted_cgi {
                   2628:     my $r=shift;
                   2629: 
                   2630:     my $buffer;
                   2631:     
                   2632:     $r->read($buffer,$r->header_in('Content-length'),0);
                   2633:     unless ($buffer=~/^(\-+\w+)\s+Content\-Disposition\:\s*form\-data/si) {
                   2634: 	my @pairs=split(/&/,$buffer);
                   2635: 	my $pair;
                   2636: 	foreach $pair (@pairs) {
                   2637: 	    my ($name,$value) = split(/=/,$pair);
                   2638: 	    $value =~ tr/+/ /;
                   2639: 	    $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
                   2640: 	    $name  =~ tr/+/ /;
                   2641: 	    $name  =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
                   2642: 	    &add_to_env("form.$name",$value);
                   2643: 	}
                   2644:     } else {
                   2645: 	my $contentsep=$1;
                   2646: 	my @lines = split (/\n/,$buffer);
                   2647: 	my $name='';
                   2648: 	my $value='';
                   2649: 	my $fname='';
                   2650: 	my $fmime='';
                   2651: 	my $i;
                   2652: 	for ($i=0;$i<=$#lines;$i++) {
                   2653: 	    if ($lines[$i]=~/^$contentsep/) {
                   2654: 		if ($name) {
                   2655: 		    chomp($value);
                   2656: 		    if ($fname) {
                   2657: 			$ENV{"form.$name.filename"}=$fname;
                   2658: 			$ENV{"form.$name.mimetype"}=$fmime;
                   2659: 		    } else {
                   2660: 			$value=~s/\s+$//s;
                   2661: 		    }
                   2662: 		    &add_to_env("form.$name",$value);
                   2663: 		}
                   2664: 		if ($i<$#lines) {
                   2665: 		    $i++;
                   2666: 		    $lines[$i]=~
                   2667: 		/Content\-Disposition\:\s*form\-data\;\s*name\=\"([^\"]+)\"/i;
                   2668: 		    $name=$1;
                   2669: 		    $value='';
                   2670: 		    if ($lines[$i]=~/filename\=\"([^\"]+)\"/i) {
                   2671: 			$fname=$1;
                   2672: 			if 
                   2673:                             ($lines[$i+1]=~/Content\-Type\:\s*([\w\-\/]+)/i) {
                   2674: 				$fmime=$1;
                   2675: 				$i++;
                   2676: 			    } else {
                   2677: 				$fmime='';
                   2678: 			    }
                   2679: 		    } else {
                   2680: 			$fname='';
                   2681: 			$fmime='';
                   2682: 		    }
                   2683: 		    $i++;
                   2684: 		}
                   2685: 	    } else {
                   2686: 		$value.=$lines[$i]."\n";
                   2687: 	    }
                   2688: 	}
                   2689:     }
                   2690:     $ENV{'request.method'}=$ENV{'REQUEST_METHOD'};
                   2691:     $r->method_number(M_GET);
                   2692:     $r->method('GET');
                   2693:     $r->headers_in->unset('Content-length');
                   2694: }
                   2695: 
1.112     bowersj2 2696: =pod
                   2697: 
                   2698: =item * get_unprocessed_cgi($query,$possible_names)
                   2699: 
                   2700: Modify the %ENV hash to contain unprocessed CGI form parameters held in
                   2701: $query.  The parameters listed in $possible_names (an array reference),
                   2702: will be set in $ENV{'form.name'} if they do not already exist.
                   2703: 
                   2704: Typically called with $ENV{'QUERY_STRING'} as the first parameter.  
                   2705: $possible_names is an ref to an array of form element names.  As an example:
                   2706: get_unprocessed_cgi($ENV{'QUERY_STRING'},['uname','udom']);
                   2707: will result in $ENV{'form.uname'} and $ENV{'form.udom'} being set.
                   2708: 
                   2709: =cut
1.1       albertel 2710: 
1.6       albertel 2711: sub get_unprocessed_cgi {
1.25      albertel 2712:   my ($query,$possible_names)= @_;
1.26      matthew  2713:   # $Apache::lonxml::debug=1;
1.16      harris41 2714:   foreach (split(/&/,$query)) {
1.6       albertel 2715:     my ($name, $value) = split(/=/,$_);
1.25      albertel 2716:     $name = &Apache::lonnet::unescape($name);
                   2717:     if (!defined($possible_names) || (grep {$_ eq $name} @$possible_names)) {
                   2718:       $value =~ tr/+/ /;
                   2719:       $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
                   2720:       &Apache::lonxml::debug("Seting :$name: to :$value:");
1.30      albertel 2721:       unless (defined($ENV{'form.'.$name})) { &add_to_env('form.'.$name,$value) };
1.25      albertel 2722:     }
1.16      harris41 2723:   }
1.6       albertel 2724: }
                   2725: 
1.112     bowersj2 2726: =pod
                   2727: 
                   2728: =item * cacheheader() 
                   2729: 
                   2730: returns cache-controlling header code
                   2731: 
                   2732: =cut
                   2733: 
1.7       albertel 2734: sub cacheheader {
1.23      www      2735:   unless ($ENV{'request.method'} eq 'GET') { return ''; }
1.8       albertel 2736:   my $date=strftime("%a, %d %b %Y %H:%M:%S GMT",gmtime);
1.7       albertel 2737:   my $output .='<meta HTTP-EQUIV="Expires" CONTENT="'.$date.'" />
                   2738:                 <meta HTTP-EQUIV="Cache-control" CONTENT="no-cache" />
                   2739:                 <meta HTTP-EQUIV="Pragma" CONTENT="no-cache" />';
                   2740:   return $output;
                   2741: }
                   2742: 
1.112     bowersj2 2743: =pod
                   2744: 
                   2745: =item * no_cache($r) 
                   2746: 
                   2747: specifies header code to not have cache
                   2748: 
                   2749: =cut
                   2750: 
1.9       albertel 2751: sub no_cache {
                   2752:   my ($r) = @_;
1.23      www      2753:   unless ($ENV{'request.method'} eq 'GET') { return ''; }
1.24      albertel 2754:   #my $date=strftime("%a, %d %b %Y %H:%M:%S GMT",gmtime);
1.9       albertel 2755:   $r->no_cache(1);
                   2756:   $r->header_out("Pragma" => "no-cache");
1.24      albertel 2757:   #$r->header_out("Expires" => $date);
1.123     www      2758: }
                   2759: 
                   2760: sub content_type {
1.181     albertel 2761:     my ($r,$type,$charset) = @_;
                   2762:     unless ($charset) {
                   2763: 	$charset=&Apache::lonlocal::current_encoding;
                   2764:     }
                   2765:     if ($charset) { $type.='; charset='.$charset; }
                   2766:     if ($r) {
                   2767: 	$r->content_type($type);
                   2768:     } else {
                   2769: 	print("Content-type: $type\n\n");
                   2770:     }
1.9       albertel 2771: }
1.25      albertel 2772: 
1.112     bowersj2 2773: =pod
                   2774: 
                   2775: =item * add_to_env($name,$value) 
                   2776: 
                   2777: adds $name to the %ENV hash with value
                   2778: $value, if $name already exists, the entry is converted to an array
                   2779: reference and $value is added to the array.
                   2780: 
                   2781: =cut
                   2782: 
1.25      albertel 2783: sub add_to_env {
                   2784:   my ($name,$value)=@_;
1.28      albertel 2785:   if (defined($ENV{$name})) {
1.27      albertel 2786:     if (ref($ENV{$name})) {
1.25      albertel 2787:       #already have multiple values
                   2788:       push(@{ $ENV{$name} },$value);
                   2789:     } else {
                   2790:       #first time seeing multiple values, convert hash entry to an arrayref
                   2791:       my $first=$ENV{$name};
                   2792:       undef($ENV{$name});
                   2793:       push(@{ $ENV{$name} },$first,$value);
                   2794:     }
                   2795:   } else {
                   2796:     $ENV{$name}=$value;
                   2797:   }
1.31      albertel 2798: }
1.149     albertel 2799: 
                   2800: =pod
                   2801: 
                   2802: =item * get_env_multiple($name) 
                   2803: 
                   2804: gets $name from the %ENV hash, it seemlessly handles the cases where multiple
                   2805: values may be defined and end up as an array ref.
                   2806: 
                   2807: returns an array of values
                   2808: 
                   2809: =cut
                   2810: 
                   2811: sub get_env_multiple {
                   2812:     my ($name) = @_;
                   2813:     my @values;
                   2814:     if (defined($ENV{$name})) {
                   2815:         # exists is it an array
                   2816:         if (ref($ENV{$name})) {
                   2817:             @values=@{ $ENV{$name} };
                   2818:         } else {
                   2819:             $values[0]=$ENV{$name};
                   2820:         }
                   2821:     }
                   2822:     return(@values);
                   2823: }
                   2824: 
1.31      albertel 2825: 
1.41      ng       2826: =pod
1.45      matthew  2827: 
                   2828: =back 
1.41      ng       2829: 
1.112     bowersj2 2830: =head1 CSV Upload/Handling functions
1.38      albertel 2831: 
1.41      ng       2832: =over 4
                   2833: 
1.112     bowersj2 2834: =item * upfile_store($r)
1.41      ng       2835: 
                   2836: Store uploaded file, $r should be the HTTP Request object,
                   2837: needs $ENV{'form.upfile'}
                   2838: returns $datatoken to be put into hidden field
                   2839: 
                   2840: =cut
1.31      albertel 2841: 
                   2842: sub upfile_store {
                   2843:     my $r=shift;
                   2844:     $ENV{'form.upfile'}=~s/\r/\n/gs;
                   2845:     $ENV{'form.upfile'}=~s/\f/\n/gs;
                   2846:     $ENV{'form.upfile'}=~s/\n+/\n/gs;
                   2847:     $ENV{'form.upfile'}=~s/\n+$//gs;
                   2848: 
                   2849:     my $datatoken=$ENV{'user.name'}.'_'.$ENV{'user.domain'}.
                   2850: 	'_enroll_'.$ENV{'request.course.id'}.'_'.time.'_'.$$;
                   2851:     {
1.158     raeburn  2852:         my $datafile = $r->dir_config('lonDaemons').
                   2853:                            '/tmp/'.$datatoken.'.tmp';
                   2854:         if ( open(my $fh,">$datafile") ) {
                   2855:             print $fh $ENV{'form.upfile'};
                   2856:             close($fh);
                   2857:         }
1.31      albertel 2858:     }
                   2859:     return $datatoken;
                   2860: }
                   2861: 
1.56      matthew  2862: =pod
                   2863: 
1.112     bowersj2 2864: =item * load_tmp_file($r)
1.41      ng       2865: 
                   2866: Load uploaded file from tmp, $r should be the HTTP Request object,
                   2867: needs $ENV{'form.datatoken'},
                   2868: sets $ENV{'form.upfile'} to the contents of the file
                   2869: 
                   2870: =cut
1.31      albertel 2871: 
                   2872: sub load_tmp_file {
                   2873:     my $r=shift;
                   2874:     my @studentdata=();
                   2875:     {
1.158     raeburn  2876:         my $studentfile = $r->dir_config('lonDaemons').
                   2877:                               '/tmp/'.$ENV{'form.datatoken'}.'.tmp';
                   2878:         if ( open(my $fh,"<$studentfile") ) {
                   2879:             @studentdata=<$fh>;
                   2880:             close($fh);
                   2881:         }
1.31      albertel 2882:     }
                   2883:     $ENV{'form.upfile'}=join('',@studentdata);
                   2884: }
                   2885: 
1.56      matthew  2886: =pod
                   2887: 
1.112     bowersj2 2888: =item * upfile_record_sep()
1.41      ng       2889: 
                   2890: Separate uploaded file into records
                   2891: returns array of records,
                   2892: needs $ENV{'form.upfile'} and $ENV{'form.upfiletype'}
                   2893: 
                   2894: =cut
1.31      albertel 2895: 
                   2896: sub upfile_record_sep {
                   2897:     if ($ENV{'form.upfiletype'} eq 'xml') {
                   2898:     } else {
                   2899: 	return split(/\n/,$ENV{'form.upfile'});
                   2900:     }
                   2901: }
                   2902: 
1.56      matthew  2903: =pod
                   2904: 
1.112     bowersj2 2905: =item * record_sep($record)
1.41      ng       2906: 
                   2907: Separate a record into fields $record should be an item from the upfile_record_sep(), needs $ENV{'form.upfiletype'}
                   2908: 
                   2909: =cut
                   2910: 
1.31      albertel 2911: sub record_sep {
                   2912:     my $record=shift;
                   2913:     my %components=();
                   2914:     if ($ENV{'form.upfiletype'} eq 'xml') {
                   2915:     } elsif ($ENV{'form.upfiletype'} eq 'space') {
                   2916:         my $i=0;
                   2917:         foreach (split(/\s+/,$record)) {
                   2918:             my $field=$_;
                   2919:             $field=~s/^(\"|\')//;
                   2920:             $field=~s/(\"|\')$//;
                   2921:             $components{$i}=$field;
                   2922:             $i++;
                   2923:         }
                   2924:     } elsif ($ENV{'form.upfiletype'} eq 'tab') {
                   2925:         my $i=0;
1.171     matthew  2926:         foreach (split(/\t/,$record)) {
1.31      albertel 2927:             my $field=$_;
                   2928:             $field=~s/^(\"|\')//;
                   2929:             $field=~s/(\"|\')$//;
                   2930:             $components{$i}=$field;
                   2931:             $i++;
                   2932:         }
                   2933:     } else {
                   2934:         my @allfields=split(/\,/,$record);
                   2935:         my $i=0;
                   2936:         my $j;
                   2937:         for ($j=0;$j<=$#allfields;$j++) {
                   2938:             my $field=$allfields[$j];
                   2939:             if ($field=~/^\s*(\"|\')/) {
                   2940: 		my $delimiter=$1;
                   2941:                 while (($field!~/$delimiter$/) && ($j<$#allfields)) {
                   2942: 		    $j++;
                   2943: 		    $field.=','.$allfields[$j];
                   2944: 		}
                   2945:                 $field=~s/^\s*$delimiter//;
                   2946:                 $field=~s/$delimiter\s*$//;
                   2947:             }
                   2948:             $components{$i}=$field;
                   2949: 	    $i++;
                   2950:         }
                   2951:     }
                   2952:     return %components;
                   2953: }
                   2954: 
1.144     matthew  2955: ######################################################
                   2956: ######################################################
                   2957: 
1.56      matthew  2958: =pod
                   2959: 
1.112     bowersj2 2960: =item * upfile_select_html()
1.41      ng       2961: 
1.144     matthew  2962: Return HTML code to select a file from the users machine and specify 
                   2963: the file type.
1.41      ng       2964: 
                   2965: =cut
                   2966: 
1.144     matthew  2967: ######################################################
                   2968: ######################################################
1.31      albertel 2969: sub upfile_select_html {
1.144     matthew  2970:     my %Types = (
                   2971:                  csv   => &mt('CSV (comma separated values, spreadsheet)'),
                   2972:                  space => &mt('Space separated'),
                   2973:                  tab   => &mt('Tabulator separated'),
                   2974: #                 xml   => &mt('HTML/XML'),
                   2975:                  );
                   2976:     my $Str = '<input type="file" name="upfile" size="50" />'.
                   2977:         '<br />Type: <select name="upfiletype">';
                   2978:     foreach my $type (sort(keys(%Types))) {
                   2979:         $Str .= '<option value="'.$type.'" >'.$Types{$type}."</option>\n";
                   2980:     }
                   2981:     $Str .= "</select>\n";
                   2982:     return $Str;
1.31      albertel 2983: }
                   2984: 
1.144     matthew  2985: ######################################################
                   2986: ######################################################
                   2987: 
1.56      matthew  2988: =pod
                   2989: 
1.112     bowersj2 2990: =item * csv_print_samples($r,$records)
1.41      ng       2991: 
                   2992: Prints a table of sample values from each column uploaded $r is an
                   2993: Apache Request ref, $records is an arrayref from
                   2994: &Apache::loncommon::upfile_record_sep
                   2995: 
                   2996: =cut
                   2997: 
1.144     matthew  2998: ######################################################
                   2999: ######################################################
1.31      albertel 3000: sub csv_print_samples {
                   3001:     my ($r,$records) = @_;
                   3002:     my (%sone,%stwo,%sthree);
                   3003:     %sone=&record_sep($$records[0]);
                   3004:     if (defined($$records[1])) {%stwo=&record_sep($$records[1]);}
                   3005:     if (defined($$records[2])) {%sthree=&record_sep($$records[2]);}
1.144     matthew  3006:     #
                   3007:     $r->print(&mt('Samples').'<br /><table border="2"><tr>');
                   3008:     foreach (sort({$a <=> $b} keys(%sone))) { 
                   3009:         $r->print('<th>'.&mt('Column&nbsp;[_1]',($_+1)).'</th>'); }
1.31      albertel 3010:     $r->print('</tr>');
                   3011:     foreach my $hash (\%sone,\%stwo,\%sthree) {
                   3012: 	$r->print('<tr>');
                   3013: 	foreach (sort({$a <=> $b} keys(%sone))) {
                   3014: 	    $r->print('<td>');
                   3015: 	    if (defined($$hash{$_})) { $r->print($$hash{$_}); }
                   3016: 	    $r->print('</td>');
                   3017: 	}
                   3018: 	$r->print('</tr>');
                   3019:     }
                   3020:     $r->print('</tr></table><br />'."\n");
                   3021: }
                   3022: 
1.144     matthew  3023: ######################################################
                   3024: ######################################################
                   3025: 
1.56      matthew  3026: =pod
                   3027: 
1.112     bowersj2 3028: =item * csv_print_select_table($r,$records,$d)
1.41      ng       3029: 
                   3030: Prints a table to create associations between values and table columns.
1.144     matthew  3031: 
1.41      ng       3032: $r is an Apache Request ref,
                   3033: $records is an arrayref from &Apache::loncommon::upfile_record_sep,
1.174     matthew  3034: $d is an array of 2 element arrays (internal name, displayed name,defaultcol)
1.41      ng       3035: 
                   3036: =cut
                   3037: 
1.144     matthew  3038: ######################################################
                   3039: ######################################################
1.31      albertel 3040: sub csv_print_select_table {
                   3041:     my ($r,$records,$d) = @_;
                   3042:     my $i=0;my %sone;
                   3043:     %sone=&record_sep($$records[0]);
1.144     matthew  3044:     $r->print(&mt('Associate columns with student attributes.')."\n".
                   3045: 	     '<table border="2"><tr>'.
                   3046:               '<th>'.&mt('Attribute').'</th>'.
                   3047:               '<th>'.&mt('Column').'</th></tr>'."\n");
1.31      albertel 3048:     foreach (@$d) {
1.174     matthew  3049: 	my ($value,$display,$defaultcol)=@{ $_ };
1.31      albertel 3050: 	$r->print('<tr><td>'.$display.'</td>');
                   3051: 
                   3052: 	$r->print('<td><select name=f'.$i.
1.32      matthew  3053: 		  ' onchange="javascript:flip(this.form,'.$i.');">');
1.31      albertel 3054: 	$r->print('<option value="none"></option>');
                   3055: 	foreach (sort({$a <=> $b} keys(%sone))) {
1.174     matthew  3056: 	    $r->print('<option value="'.$_.'"'.
                   3057:                       ($_ eq $defaultcol ? ' selected ' : '').
                   3058:                       '>Column '.($_+1).'</option>');
1.31      albertel 3059: 	}
                   3060: 	$r->print('</select></td></tr>'."\n");
                   3061: 	$i++;
                   3062:     }
                   3063:     $i--;
                   3064:     return $i;
                   3065: }
1.56      matthew  3066: 
1.144     matthew  3067: ######################################################
                   3068: ######################################################
                   3069: 
1.56      matthew  3070: =pod
1.31      albertel 3071: 
1.112     bowersj2 3072: =item * csv_samples_select_table($r,$records,$d)
1.41      ng       3073: 
                   3074: Prints a table of sample values from the upload and can make associate samples to internal names.
                   3075: 
                   3076: $r is an Apache Request ref,
                   3077: $records is an arrayref from &Apache::loncommon::upfile_record_sep,
                   3078: $d is an array of 2 element arrays (internal name, displayed name)
                   3079: 
                   3080: =cut
                   3081: 
1.144     matthew  3082: ######################################################
                   3083: ######################################################
1.31      albertel 3084: sub csv_samples_select_table {
                   3085:     my ($r,$records,$d) = @_;
                   3086:     my %sone; my %stwo; my %sthree;
                   3087:     my $i=0;
1.144     matthew  3088:     #
                   3089:     $r->print('<table border=2><tr><th>'.
                   3090:               &mt('Field').'</th><th>'.&mt('Samples').'</th></tr>');
1.31      albertel 3091:     %sone=&record_sep($$records[0]);
                   3092:     if (defined($$records[1])) {%stwo=&record_sep($$records[1]);}
                   3093:     if (defined($$records[2])) {%sthree=&record_sep($$records[2]);}
1.144     matthew  3094:     #
1.31      albertel 3095:     foreach (sort keys %sone) {
1.144     matthew  3096: 	$r->print('<tr><td><select name="f'.$i.'"'.
1.32      matthew  3097: 		  ' onchange="javascript:flip(this.form,'.$i.');">');
1.31      albertel 3098: 	foreach (@$d) {
1.174     matthew  3099: 	    my ($value,$display,$defaultcol)=@{ $_ };
                   3100: 	    $r->print('<option value="'.$value.'"'.
                   3101:                       ($i eq $defaultcol ? ' selected ':'').'>'.
                   3102:                       $display.'</option>');
1.31      albertel 3103: 	}
                   3104: 	$r->print('</select></td><td>');
                   3105: 	if (defined($sone{$_})) { $r->print($sone{$_}."</br>\n"); }
                   3106: 	if (defined($stwo{$_})) { $r->print($stwo{$_}."</br>\n"); }
                   3107: 	if (defined($sthree{$_})) { $r->print($sthree{$_}."</br>\n"); }
                   3108: 	$r->print('</td></tr>');
                   3109: 	$i++;
                   3110:     }
                   3111:     $i--;
                   3112:     return($i);
1.115     matthew  3113: }
                   3114: 
1.144     matthew  3115: ######################################################
                   3116: ######################################################
                   3117: 
1.115     matthew  3118: =pod
                   3119: 
                   3120: =item clean_excel_name($name)
                   3121: 
                   3122: Returns a replacement for $name which does not contain any illegal characters.
                   3123: 
                   3124: =cut
                   3125: 
1.144     matthew  3126: ######################################################
                   3127: ######################################################
1.115     matthew  3128: sub clean_excel_name {
                   3129:     my ($name) = @_;
                   3130:     $name =~ s/[:\*\?\/\\]//g;
                   3131:     if (length($name) > 31) {
                   3132:         $name = substr($name,0,31);
                   3133:     }
                   3134:     return $name;
1.25      albertel 3135: }
1.84      albertel 3136: 
1.85      albertel 3137: =pod
                   3138: 
1.112     bowersj2 3139: =item * check_if_partid_hidden($id,$symb,$udom,$uname)
1.85      albertel 3140: 
                   3141: Returns either 1 or undef
                   3142: 
                   3143: 1 if the part is to be hidden, undef if it is to be shown
                   3144: 
                   3145: Arguments are:
                   3146: 
                   3147: $id the id of the part to be checked
                   3148: $symb, optional the symb of the resource to check
                   3149: $udom, optional the domain of the user to check for
                   3150: $uname, optional the username of the user to check for
                   3151: 
                   3152: =cut
1.84      albertel 3153: 
                   3154: sub check_if_partid_hidden {
                   3155:     my ($id,$symb,$udom,$uname) = @_;
1.133     albertel 3156:     my $hiddenparts=&Apache::lonnet::EXT('resource.0.hiddenparts',
1.84      albertel 3157: 					 $symb,$udom,$uname);
1.141     albertel 3158:     my $truth=1;
                   3159:     #if the string starts with !, then the list is the list to show not hide
                   3160:     if ($hiddenparts=~s/^\s*!//) { $truth=undef; }
1.84      albertel 3161:     my @hiddenlist=split(/,/,$hiddenparts);
                   3162:     foreach my $checkid (@hiddenlist) {
1.141     albertel 3163: 	if ($checkid =~ /^\s*\Q$id\E\s*$/) { return $truth; }
1.84      albertel 3164:     }
1.141     albertel 3165:     return !$truth;
1.84      albertel 3166: }
1.127     matthew  3167: 
1.138     matthew  3168: 
                   3169: ############################################################
                   3170: ############################################################
                   3171: 
                   3172: =pod
                   3173: 
1.157     matthew  3174: =back 
                   3175: 
1.138     matthew  3176: =head1 cgi-bin script and graphing routines
                   3177: 
1.157     matthew  3178: =over 4
                   3179: 
1.138     matthew  3180: =item get_cgi_id
                   3181: 
                   3182: Inputs: none
                   3183: 
                   3184: Returns an id which can be used to pass environment variables
                   3185: to various cgi-bin scripts.  These environment variables will
                   3186: be removed from the users environment after a given time by
                   3187: the routine &Apache::lonnet::transfer_profile_to_env.
                   3188: 
                   3189: =cut
                   3190: 
                   3191: ############################################################
                   3192: ############################################################
1.152     albertel 3193: my $uniq=0;
1.136     matthew  3194: sub get_cgi_id {
1.154     albertel 3195:     $uniq=($uniq+1)%100000;
1.152     albertel 3196:     return (time.'_'.$uniq);
1.136     matthew  3197: }
                   3198: 
1.127     matthew  3199: ############################################################
                   3200: ############################################################
                   3201: 
                   3202: =pod
                   3203: 
1.134     matthew  3204: =item DrawBarGraph
1.127     matthew  3205: 
1.138     matthew  3206: Facilitates the plotting of data in a (stacked) bar graph.
                   3207: Puts plot definition data into the users environment in order for 
                   3208: graph.png to plot it.  Returns an <img> tag for the plot.
                   3209: The bars on the plot are labeled '1','2',...,'n'.
                   3210: 
                   3211: Inputs:
                   3212: 
                   3213: =over 4
                   3214: 
                   3215: =item $Title: string, the title of the plot
                   3216: 
                   3217: =item $xlabel: string, text describing the X-axis of the plot
                   3218: 
                   3219: =item $ylabel: string, text describing the Y-axis of the plot
                   3220: 
                   3221: =item $Max: scalar, the maximum Y value to use in the plot
                   3222: If $Max is < any data point, the graph will not be rendered.
                   3223: 
1.140     matthew  3224: =item $colors: array ref holding the colors to be used for the data sets when
1.138     matthew  3225: they are plotted.  If undefined, default values will be used.
                   3226: 
1.178     matthew  3227: =item $labels: array ref holding the labels to use on the x-axis for the bars.
                   3228: 
1.138     matthew  3229: =item @Values: An array of array references.  Each array reference holds data
                   3230: to be plotted in a stacked bar chart.
                   3231: 
                   3232: =back
                   3233: 
                   3234: Returns:
                   3235: 
                   3236: An <img> tag which references graph.png and the appropriate identifying
                   3237: information for the plot.
                   3238: 
1.127     matthew  3239: =cut
                   3240: 
                   3241: ############################################################
                   3242: ############################################################
1.134     matthew  3243: sub DrawBarGraph {
1.178     matthew  3244:     my ($Title,$xlabel,$ylabel,$Max,$colors,$labels,@Values)=@_;
1.134     matthew  3245:     #
                   3246:     if (! defined($colors)) {
                   3247:         $colors = ['#33ff00', 
                   3248:                   '#0033cc', '#990000', '#aaaa66', '#663399', '#ff9933',
                   3249:                   '#66ccff', '#ff9999', '#cccc33', '#660000', '#33cc66',
                   3250:                   ]; 
                   3251:     }
1.127     matthew  3252:     #
1.136     matthew  3253:     my $identifier = &get_cgi_id();
                   3254:     my $id = 'cgi.'.$identifier;        
1.129     matthew  3255:     if (! @Values || ref($Values[0]) ne 'ARRAY') {
1.127     matthew  3256:         return '';
                   3257:     }
1.129     matthew  3258:     my $NumBars = scalar(@{$Values[0]});
                   3259:     my %ValuesHash;
                   3260:     my $NumSets=1;
                   3261:     foreach my $array (@Values) {
                   3262:         next if (! ref($array));
1.136     matthew  3263:         $ValuesHash{$id.'.data.'.$NumSets++} = 
1.132     matthew  3264:             join(',',@$array);
1.129     matthew  3265:     }
1.127     matthew  3266:     #
1.136     matthew  3267:     my ($height,$width,$xskip,$bar_width) = (200,120,1,15);
                   3268:     if ($NumBars < 10) {
                   3269:         $width = 120+$NumBars*15;
                   3270:         $xskip = 1;
                   3271:         $bar_width = 15;
                   3272:     } elsif ($NumBars <= 25) {
                   3273:         $width = 120+$NumBars*11;
                   3274:         $xskip = 5;
                   3275:         $bar_width = 8;
                   3276:     } elsif ($NumBars <= 50) {
                   3277:         $width = 120+$NumBars*8;
                   3278:         $xskip = 5;
                   3279:         $bar_width = 4;
                   3280:     } else {
                   3281:         $width = 120+$NumBars*8;
                   3282:         $xskip = 5;
                   3283:         $bar_width = 4;
                   3284:     }
                   3285:     #
                   3286:     my @Labels;
1.178     matthew  3287:     if (defined($labels)) {
                   3288:         @Labels = @$labels;
                   3289:     } else {
                   3290:         for (my $i=0;$i<@{$Values[0]};$i++) {
                   3291:             push (@Labels,$i+1);
                   3292:         }
1.136     matthew  3293:     }
                   3294:     #
1.137     matthew  3295:     $Max = 1 if ($Max < 1);
                   3296:     if ( int($Max) < $Max ) {
                   3297:         $Max++;
                   3298:         $Max = int($Max);
                   3299:     }
1.127     matthew  3300:     $Title  = '' if (! defined($Title));
                   3301:     $xlabel = '' if (! defined($xlabel));
                   3302:     $ylabel = '' if (! defined($ylabel));
1.136     matthew  3303:     $ValuesHash{$id.'.title'}    = &Apache::lonnet::escape($Title);
                   3304:     $ValuesHash{$id.'.xlabel'}   = &Apache::lonnet::escape($xlabel);
                   3305:     $ValuesHash{$id.'.ylabel'}   = &Apache::lonnet::escape($ylabel);
1.137     matthew  3306:     $ValuesHash{$id.'.y_max_value'} = $Max;
1.136     matthew  3307:     $ValuesHash{$id.'.NumBars'}  = $NumBars;
                   3308:     $ValuesHash{$id.'.NumSets'}  = $NumSets;
                   3309:     $ValuesHash{$id.'.PlotType'} = 'bar';
                   3310:     $ValuesHash{$id.'.Colors'}   = join(',',@{$colors});
                   3311:     $ValuesHash{$id.'.height'}   = $height;
                   3312:     $ValuesHash{$id.'.width'}    = $width;
                   3313:     $ValuesHash{$id.'.xskip'}    = $xskip;
                   3314:     $ValuesHash{$id.'.bar_width'} = $bar_width;
                   3315:     $ValuesHash{$id.'.labels'} = join(',',@Labels);
1.127     matthew  3316:     #
1.137     matthew  3317:     &Apache::lonnet::appenv(%ValuesHash);
                   3318:     return '<img src="/cgi-bin/graph.png?'.$identifier.'" border="1" />';
                   3319: }
                   3320: 
                   3321: ############################################################
                   3322: ############################################################
                   3323: 
                   3324: =pod
                   3325: 
                   3326: =item DrawXYGraph
                   3327: 
1.138     matthew  3328: Facilitates the plotting of data in an XY graph.
                   3329: Puts plot definition data into the users environment in order for 
                   3330: graph.png to plot it.  Returns an <img> tag for the plot.
                   3331: 
                   3332: Inputs:
                   3333: 
                   3334: =over 4
                   3335: 
                   3336: =item $Title: string, the title of the plot
                   3337: 
                   3338: =item $xlabel: string, text describing the X-axis of the plot
                   3339: 
                   3340: =item $ylabel: string, text describing the Y-axis of the plot
                   3341: 
                   3342: =item $Max: scalar, the maximum Y value to use in the plot
                   3343: If $Max is < any data point, the graph will not be rendered.
                   3344: 
                   3345: =item $colors: Array ref containing the hex color codes for the data to be 
                   3346: plotted in.  If undefined, default values will be used.
                   3347: 
                   3348: =item $Xlabels: Array ref containing the labels to be used for the X-axis.
                   3349: 
                   3350: =item $Ydata: Array ref containing Array refs.  
1.185     www      3351: Each of the contained arrays will be plotted as a separate curve.
1.138     matthew  3352: 
                   3353: =item %Values: hash indicating or overriding any default values which are 
                   3354: passed to graph.png.  
                   3355: Possible values are: width, xskip, x_ticks, x_tick_offset, among others.
                   3356: 
                   3357: =back
                   3358: 
                   3359: Returns:
                   3360: 
                   3361: An <img> tag which references graph.png and the appropriate identifying
                   3362: information for the plot.
                   3363: 
1.137     matthew  3364: =cut
                   3365: 
                   3366: ############################################################
                   3367: ############################################################
                   3368: sub DrawXYGraph {
                   3369:     my ($Title,$xlabel,$ylabel,$Max,$colors,$Xlabels,$Ydata,%Values)=@_;
                   3370:     #
                   3371:     # Create the identifier for the graph
                   3372:     my $identifier = &get_cgi_id();
                   3373:     my $id = 'cgi.'.$identifier;
                   3374:     #
                   3375:     $Title  = '' if (! defined($Title));
                   3376:     $xlabel = '' if (! defined($xlabel));
                   3377:     $ylabel = '' if (! defined($ylabel));
                   3378:     my %ValuesHash = 
                   3379:         (
                   3380:          $id.'.title'  => &Apache::lonnet::escape($Title),
                   3381:          $id.'.xlabel' => &Apache::lonnet::escape($xlabel),
                   3382:          $id.'.ylabel' => &Apache::lonnet::escape($ylabel),
                   3383:          $id.'.y_max_value'=> $Max,
                   3384:          $id.'.labels'     => join(',',@$Xlabels),
                   3385:          $id.'.PlotType'   => 'XY',
                   3386:          );
                   3387:     #
                   3388:     if (defined($colors) && ref($colors) eq 'ARRAY') {
                   3389:         $ValuesHash{$id.'.Colors'}   = join(',',@{$colors});
                   3390:     }
                   3391:     #
                   3392:     if (! ref($Ydata) || ref($Ydata) ne 'ARRAY') {
                   3393:         return '';
                   3394:     }
                   3395:     my $NumSets=1;
1.138     matthew  3396:     foreach my $array (@{$Ydata}){
1.137     matthew  3397:         next if (! ref($array));
                   3398:         $ValuesHash{$id.'.data.'.$NumSets++} = join(',',@$array);
                   3399:     }
1.138     matthew  3400:     $ValuesHash{$id.'.NumSets'} = $NumSets-1;
1.137     matthew  3401:     #
                   3402:     # Deal with other parameters
                   3403:     while (my ($key,$value) = each(%Values)) {
                   3404:         $ValuesHash{$id.'.'.$key} = $value;
1.127     matthew  3405:     }
                   3406:     #
1.136     matthew  3407:     &Apache::lonnet::appenv(%ValuesHash);
                   3408:     return '<img src="/cgi-bin/graph.png?'.$identifier.'" border="1" />';
                   3409: }
                   3410: 
                   3411: ############################################################
                   3412: ############################################################
                   3413: 
                   3414: =pod
                   3415: 
1.138     matthew  3416: =item DrawXYYGraph
                   3417: 
                   3418: Facilitates the plotting of data in an XY graph with two Y axes.
                   3419: Puts plot definition data into the users environment in order for 
                   3420: graph.png to plot it.  Returns an <img> tag for the plot.
                   3421: 
                   3422: Inputs:
                   3423: 
                   3424: =over 4
                   3425: 
                   3426: =item $Title: string, the title of the plot
                   3427: 
                   3428: =item $xlabel: string, text describing the X-axis of the plot
                   3429: 
                   3430: =item $ylabel: string, text describing the Y-axis of the plot
                   3431: 
                   3432: =item $colors: Array ref containing the hex color codes for the data to be 
                   3433: plotted in.  If undefined, default values will be used.
                   3434: 
                   3435: =item $Xlabels: Array ref containing the labels to be used for the X-axis.
                   3436: 
                   3437: =item $Ydata1: The first data set
                   3438: 
                   3439: =item $Min1: The minimum value of the left Y-axis
                   3440: 
                   3441: =item $Max1: The maximum value of the left Y-axis
                   3442: 
                   3443: =item $Ydata2: The second data set
                   3444: 
                   3445: =item $Min2: The minimum value of the right Y-axis
                   3446: 
                   3447: =item $Max2: The maximum value of the left Y-axis
                   3448: 
                   3449: =item %Values: hash indicating or overriding any default values which are 
                   3450: passed to graph.png.  
                   3451: Possible values are: width, xskip, x_ticks, x_tick_offset, among others.
                   3452: 
                   3453: =back
                   3454: 
                   3455: Returns:
                   3456: 
                   3457: An <img> tag which references graph.png and the appropriate identifying
                   3458: information for the plot.
1.136     matthew  3459: 
                   3460: =cut
                   3461: 
                   3462: ############################################################
                   3463: ############################################################
1.137     matthew  3464: sub DrawXYYGraph {
                   3465:     my ($Title,$xlabel,$ylabel,$colors,$Xlabels,$Ydata1,$Min1,$Max1,
                   3466:                                         $Ydata2,$Min2,$Max2,%Values)=@_;
1.136     matthew  3467:     #
                   3468:     # Create the identifier for the graph
                   3469:     my $identifier = &get_cgi_id();
                   3470:     my $id = 'cgi.'.$identifier;
                   3471:     #
                   3472:     $Title  = '' if (! defined($Title));
                   3473:     $xlabel = '' if (! defined($xlabel));
                   3474:     $ylabel = '' if (! defined($ylabel));
                   3475:     my %ValuesHash = 
                   3476:         (
                   3477:          $id.'.title'  => &Apache::lonnet::escape($Title),
                   3478:          $id.'.xlabel' => &Apache::lonnet::escape($xlabel),
                   3479:          $id.'.ylabel' => &Apache::lonnet::escape($ylabel),
                   3480:          $id.'.labels' => join(',',@$Xlabels),
                   3481:          $id.'.PlotType' => 'XY',
                   3482:          $id.'.NumSets' => 2,
1.137     matthew  3483:          $id.'.two_axes' => 1,
                   3484:          $id.'.y1_max_value' => $Max1,
                   3485:          $id.'.y1_min_value' => $Min1,
                   3486:          $id.'.y2_max_value' => $Max2,
                   3487:          $id.'.y2_min_value' => $Min2,
1.136     matthew  3488:          );
                   3489:     #
1.137     matthew  3490:     if (defined($colors) && ref($colors) eq 'ARRAY') {
                   3491:         $ValuesHash{$id.'.Colors'}   = join(',',@{$colors});
                   3492:     }
                   3493:     #
                   3494:     if (! ref($Ydata1) || ref($Ydata1) ne 'ARRAY' ||
                   3495:         ! ref($Ydata2) || ref($Ydata2) ne 'ARRAY'){
1.136     matthew  3496:         return '';
                   3497:     }
                   3498:     my $NumSets=1;
1.137     matthew  3499:     foreach my $array ($Ydata1,$Ydata2){
1.136     matthew  3500:         next if (! ref($array));
                   3501:         $ValuesHash{$id.'.data.'.$NumSets++} = join(',',@$array);
1.137     matthew  3502:     }
                   3503:     #
                   3504:     # Deal with other parameters
                   3505:     while (my ($key,$value) = each(%Values)) {
                   3506:         $ValuesHash{$id.'.'.$key} = $value;
1.136     matthew  3507:     }
                   3508:     #
                   3509:     &Apache::lonnet::appenv(%ValuesHash);
1.130     albertel 3510:     return '<img src="/cgi-bin/graph.png?'.$identifier.'" border="1" />';
1.139     matthew  3511: }
                   3512: 
                   3513: ############################################################
                   3514: ############################################################
                   3515: 
                   3516: =pod
                   3517: 
1.157     matthew  3518: =back 
                   3519: 
1.139     matthew  3520: =head1 Statistics helper routines?  
                   3521: 
                   3522: Bad place for them but what the hell.
                   3523: 
1.157     matthew  3524: =over 4
                   3525: 
1.139     matthew  3526: =item &chartlink
                   3527: 
                   3528: Returns a link to the chart for a specific student.  
                   3529: 
                   3530: Inputs:
                   3531: 
                   3532: =over 4
                   3533: 
                   3534: =item $linktext: The text of the link
                   3535: 
                   3536: =item $sname: The students username
                   3537: 
                   3538: =item $sdomain: The students domain
                   3539: 
                   3540: =back
                   3541: 
1.157     matthew  3542: =back
                   3543: 
1.139     matthew  3544: =cut
                   3545: 
                   3546: ############################################################
                   3547: ############################################################
                   3548: sub chartlink {
                   3549:     my ($linktext, $sname, $sdomain) = @_;
                   3550:     my $link = '<a href="/adm/statistics?reportSelected=student_assessment'.
                   3551:         '&SelectedStudent='.&Apache::lonnet::escape($sname.':'.$sdomain).
                   3552:         '&chartoutputmode='.HTML::Entities::encode('html, with all links').
                   3553:        '">'.$linktext.'</a>';
1.153     matthew  3554: }
                   3555: 
                   3556: #######################################################
                   3557: #######################################################
                   3558: 
                   3559: =pod
                   3560: 
                   3561: =head1 Course Environment Routines
1.157     matthew  3562: 
                   3563: =over 4
1.153     matthew  3564: 
                   3565: =item &restore_course_settings 
                   3566: 
                   3567: =item &store_course_settings
                   3568: 
                   3569: Restores/Store indicated form parameters from the course environment.
                   3570: Will not overwrite existing values of the form parameters.
                   3571: 
                   3572: Inputs: 
                   3573: a scalar describing the data (e.g. 'chart', 'problem_analysis')
                   3574: 
                   3575: a hash ref describing the data to be stored.  For example:
                   3576:    
                   3577: %Save_Parameters = ('Status' => 'scalar',
                   3578:     'chartoutputmode' => 'scalar',
                   3579:     'chartoutputdata' => 'scalar',
                   3580:     'Section' => 'array',
                   3581:     'StudentData' => 'array',
                   3582:     'Maps' => 'array');
                   3583: 
                   3584: Returns: both routines return nothing
                   3585: 
                   3586: =cut
                   3587: 
                   3588: #######################################################
                   3589: #######################################################
                   3590: sub store_course_settings {
                   3591:     # save to the environment
                   3592:     # appenv the same items, just to be safe
                   3593:     my $courseid = $ENV{'request.course.id'};
                   3594:     my $coursedom = $ENV{'course.'.$courseid.'.domain'};
                   3595:     my ($prefix,$Settings) = @_;
                   3596:     my %SaveHash;
                   3597:     my %AppHash;
                   3598:     while (my ($setting,$type) = each(%$Settings)) {
1.176     albertel 3599:         my $basename = 'internal.'.$prefix.'.'.$setting;
1.153     matthew  3600:         my $envname = 'course.'.$courseid.'.'.$basename;
                   3601:         if (exists($ENV{'form.'.$setting})) {
                   3602:             # Save this value away
                   3603:             if ($type eq 'scalar' &&
                   3604:                 (! exists($ENV{$envname}) || 
                   3605:                  $ENV{$envname} ne $ENV{'form.'.$setting})) {
                   3606:                 $SaveHash{$basename} = $ENV{'form.'.$setting};
                   3607:                 $AppHash{$envname}   = $ENV{'form.'.$setting};
                   3608:             } elsif ($type eq 'array') {
                   3609:                 my $stored_form;
                   3610:                 if (ref($ENV{'form.'.$setting})) {
                   3611:                     $stored_form = join(',',
                   3612:                                         map {
                   3613:                                             &Apache::lonnet::escape($_);
                   3614:                                         } sort(@{$ENV{'form.'.$setting}}));
                   3615:                 } else {
                   3616:                     $stored_form = 
                   3617:                         &Apache::lonnet::escape($ENV{'form.'.$setting});
                   3618:                 }
                   3619:                 # Determine if the array contents are the same.
                   3620:                 if ($stored_form ne $ENV{$envname}) {
                   3621:                     $SaveHash{$basename} = $stored_form;
                   3622:                     $AppHash{$envname}   = $stored_form;
                   3623:                 }
                   3624:             }
                   3625:         }
                   3626:     }
                   3627:     my $put_result = &Apache::lonnet::put('environment',\%SaveHash,
                   3628:                                           $coursedom,
                   3629:                                           $ENV{'course.'.$courseid.'.num'});
                   3630:     if ($put_result !~ /^(ok|delayed)/) {
                   3631:         &Apache::lonnet::logthis('unable to save form parameters, '.
                   3632:                                  'got error:'.$put_result);
                   3633:     }
                   3634:     # Make sure these settings stick around in this session, too
                   3635:     &Apache::lonnet::appenv(%AppHash);
                   3636:     return;
                   3637: }
                   3638: 
                   3639: sub restore_course_settings {
                   3640:     my $courseid = $ENV{'request.course.id'};
                   3641:     my ($prefix,$Settings) = @_;
                   3642:     while (my ($setting,$type) = each(%$Settings)) {
                   3643:         next if (exists($ENV{'form.'.$setting}));
1.176     albertel 3644:         my $envname = 'course.'.$courseid.'.internal.'.$prefix.
1.153     matthew  3645:             '.'.$setting;
                   3646:         if (exists($ENV{$envname})) {
                   3647:             if ($type eq 'scalar') {
                   3648:                 $ENV{'form.'.$setting} = $ENV{$envname};
                   3649:             } elsif ($type eq 'array') {
                   3650:                 $ENV{'form.'.$setting} = [ 
                   3651:                                            map { 
                   3652:                                                &Apache::lonnet::unescape($_); 
                   3653:                                            } split(',',$ENV{$envname})
                   3654:                                            ];
                   3655:             }
                   3656:         }
                   3657:     }
1.127     matthew  3658: }
                   3659: 
                   3660: ############################################################
                   3661: ############################################################
1.154     albertel 3662: 
                   3663: sub propath {
                   3664:     my ($udom,$uname)=@_;
                   3665:     $udom=~s/\W//g;
                   3666:     $uname=~s/\W//g;
                   3667:     my $subdir=$uname.'__';
                   3668:     $subdir =~ s/(.)(.)(.).*/$1\/$2\/$3/;
                   3669:     my $proname="$Apache::lonnet::perlvar{'lonUsersDir'}/$udom/$subdir/$uname";
                   3670:     return $proname;
1.156     albertel 3671: } 
                   3672: 
                   3673: sub icon {
                   3674:     my ($file)=@_;
1.168     albertel 3675:     my $curfext = (split(/\./,$file))[-1];
                   3676:     my $iconname=$Apache::lonnet::perlvar{'lonIconsURL'}.'/unknown.gif';
1.156     albertel 3677:     my $embstyle = &Apache::loncommon::fileembstyle($curfext);
1.168     albertel 3678:     if (!(!defined($embstyle) || $embstyle eq 'unk' || $embstyle eq 'hdn')) {
                   3679: 	if (-e  $Apache::lonnet::perlvar{'lonDocRoot'}.'/'.
                   3680: 	          $Apache::lonnet::perlvar{'lonIconsURL'}.'/'.
                   3681: 	            $curfext.".gif") {
                   3682: 	    $iconname=$Apache::lonnet::perlvar{'lonIconsURL'}.'/'.
                   3683: 		$curfext.".gif";
                   3684: 	}
                   3685:     }
                   3686:     return $iconname;
1.154     albertel 3687: } 
1.84      albertel 3688: 
1.41      ng       3689: =pod
                   3690: 
                   3691: =back
                   3692: 
1.112     bowersj2 3693: =cut
1.41      ng       3694: 
1.112     bowersj2 3695: 1;
                   3696: __END__;
1.41      ng       3697: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>
500 Internal Server Error

Internal Server Error

The server encountered an internal error or misconfiguration and was unable to complete your request.

Please contact the server administrator at root@localhost to inform them of the time this error occurred, and the actions you performed just before this error.

More information about this error may be available in the server error log.