--- loncom/interface/loncommon.pm 2005/02/17 08:29:42 1.250 +++ loncom/interface/loncommon.pm 2005/06/06 20:31:24 1.267 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # a pile of common routines # -# $Id: loncommon.pm,v 1.250 2005/02/17 08:29:42 albertel Exp $ +# $Id: loncommon.pm,v 1.267 2005/06/06 20:31:24 www Exp $ # # Copyright Michigan State University Board of Trustees # @@ -55,7 +55,7 @@ redundancy from other modules and increa package Apache::loncommon; use strict; -use Apache::lonnet(); +use Apache::lonnet; use GDBM_File; use POSIX qw(strftime mktime); use Apache::Constants qw(:common :http :methods); @@ -311,8 +311,8 @@ END } sub lastresurl { - if ($ENV{'environment.lastresurl'}) { - return $ENV{'environment.lastresurl'} + if ($env{'environment.lastresurl'}) { + return $env{'environment.lastresurl'} } else { return '/res'; } @@ -329,9 +329,9 @@ sub storeresurl { sub studentbrowser_javascript { unless ( - (($ENV{'request.course.id'}) && - (&Apache::lonnet::allowed('srm',$ENV{'request.course.id'}))) - || ($ENV{'request.role'}=~/^(au|dc|su)/) + (($env{'request.course.id'}) && + (&Apache::lonnet::allowed('srm',$env{'request.course.id'}))) + || ($env{'request.role'}=~/^(au|dc|su)/) ) { return ''; } return (<<'ENDSTDBRW'); <script type="text/javascript" language="Javascript" > @@ -360,14 +360,14 @@ ENDSTDBRW sub selectstudent_link { my ($form,$unameele,$udomele)=@_; - if ($ENV{'request.course.id'}) { - unless (&Apache::lonnet::allowed('srm',$ENV{'request.course.id'})) { + if ($env{'request.course.id'}) { + unless (&Apache::lonnet::allowed('srm',$env{'request.course.id'})) { return ''; } return "<a href='".'javascript:openstdbrowser("'.$form.'","'.$unameele. '","'.$udomele.'");'."'>".&mt('Select User')."</a>"; } - if ($ENV{'request.role'}=~/^(au|dc|su)/) { + if ($env{'request.role'}=~/^(au|dc|su)/) { return "<a href='".'javascript:openstdbrowser("'.$form.'","'.$unameele. '","'.$udomele.'",1);'."'>".&mt('Select User')."</a>"; } @@ -547,7 +547,7 @@ END $result .= "<select size=\"1\" name=\"$firstselectname\" onchange=\"select1_changed()\">\n"; foreach my $value (sort(keys(%$hashref))) { $result.=" <option value=\"$value\" "; - $result.=" selected=\"true\" " if ($value eq $firstdefault); + $result.=" selected=\"selected\" " if ($value eq $firstdefault); $result.=">".&mt($hashref->{$value}->{'text'})."</option>\n"; } $result .= "</select>\n"; @@ -557,7 +557,7 @@ END my $seconddefault = $hashref->{$firstdefault}->{'default'}; foreach my $value (sort(keys(%select2))) { $result.=" <option value=\"$value\" "; - $result.=" selected=\"true\" " if ($value eq $seconddefault); + $result.=" selected=\"selected\" " if ($value eq $seconddefault); $result.=">".&mt($select2{$value})."</option>\n"; } $result .= "</select>\n"; @@ -593,8 +593,8 @@ sub help_open_topic { my ($topic, $text, $stayOnPage, $width, $height) = @_; $text = "" if (not defined $text); $stayOnPage = 0 if (not defined $stayOnPage); - if ($ENV{'browser.interface'} eq 'textual' || - $ENV{'environment.remote'} eq 'off' ) { + if ($env{'browser.interface'} eq 'textual' || + $env{'environment.remote'} eq 'off' ) { $stayOnPage=1; } $width = 350 if (not defined $width); @@ -659,8 +659,8 @@ sub help_open_menu { my ($color,$topic,$component_help,$function,$faq,$bug,$stayOnPage,$width,$height,$text) = @_; $text = "" if (not defined $text); $stayOnPage = 0 if (not defined $stayOnPage); - if ($ENV{'browser.interface'} eq 'textual' || - $ENV{'environment.remote'} eq 'off' ) { + if ($env{'browser.interface'} eq 'textual' || + $env{'environment.remote'} eq 'off' ) { $stayOnPage=1; } $width = 620 if (not defined $width); @@ -673,7 +673,6 @@ sub help_open_menu { foreach (\$color,\$function,\$topic,\$component_help,\$faq,\$bug,\$origurl) { $$_ = &Apache::lonnet::escape($$_); } - if (!$stayOnPage) { $link = "javascript:helpMenu('open')"; } else { @@ -684,20 +683,22 @@ sub help_open_menu { my $template; if ($text ne "") { $template .= - "<table bgcolor='#773311' cellspacing='1' cellpadding='1' border='0'><tr>". - "<td bgcolor='#886622'><a href=\"$link\"><font color='#FFFFFF' size='2'>$text</font></a>"; + "<table bgcolor='#CC3300' cellspacing='1' cellpadding='1' border='0'><tr>". + "<td bgcolor='#CC6600'><a href=\"$link\"><font color='#FFFFFF' size='2'>$text</font></a>"; } + my $nothing=&Apache::lonhtmlcommon::javascript_nothing(); my $html=&Apache::lonxml::xmlbegin(); my $helpicon=&lonhttpdurl("/adm/lonIcons/helpgateway.gif"); $template .= <<"ENDTEMPLATE"; <script type="text/javascript"> -//<!-- BEGIN LON-CAPA Internal +// <!-- BEGIN LON-CAPA Internal +// <![CDATA[ function helpMenu(target) { var caller = this; if (target == 'open') { var newWindow = null; try { - newWindow = window.open("/adm/rat/empty.html","helpmenu","HEIGHT=$height,WIDTH=$width,resizable=yes,scrollbars=yes" ) + newWindow = window.open($nothing,"helpmenu","HEIGHT=$height,WIDTH=$width,resizable=yes,scrollbars=yes" ) } catch(error) { writeHelp(caller); @@ -711,12 +712,13 @@ function helpMenu(target) { return; } function writeHelp(caller) { - caller.document.write('$html<head><title>LON-CAPA Help Menu</title><meta http-equiv="pragma" content="no-cache"></head>') - caller.document.write("<frameset rows='105,*' border='0'><frame name='bannerframe' src='$banner_link'><frame name='bodyframe' src='$details_link'></frameset>") - caller.document.write("</html>") + caller.document.writeln('$html<head><title>LON-CAPA Help Menu</title><meta http-equiv="pragma" content="no-cache"></head>') + caller.document.writeln("<frameset rows='105,*' border='0'><frame name='bannerframe' src='$banner_link'><frame name='bodyframe' src='$details_link'></frameset>") + caller.document.writeln("</html>") caller.document.close() caller.focus() } +// ]]> // END LON-CAPA Internal --> </script> <a href="$link" title="$title"><img src="$helpicon" border="0" alt="(Help Menu)" /></a> @@ -740,12 +742,12 @@ ENDTEMPLATE sub help_open_bug { my ($topic, $text, $stayOnPage, $width, $height) = @_; - unless ($ENV{'user.adv'}) { return ''; } + unless ($env{'user.adv'}) { return ''; } unless ($Apache::lonnet::perlvar{'BugzillaHost'}) { return ''; } $text = "" if (not defined $text); $stayOnPage = 0 if (not defined $stayOnPage); - if ($ENV{'browser.interface'} eq 'textual' || - $ENV{'environment.remote'} eq 'off' ) { + if ($env{'browser.interface'} eq 'textual' || + $env{'environment.remote'} eq 'off' ) { $stayOnPage=1; } $width = 600 if (not defined $width); @@ -785,12 +787,12 @@ ENDTEMPLATE sub help_open_faq { my ($topic, $text, $stayOnPage, $width, $height) = @_; - unless ($ENV{'user.adv'}) { return ''; } + unless ($env{'user.adv'}) { return ''; } unless ($Apache::lonnet::perlvar{'FAQHost'}) { return ''; } $text = "" if (not defined $text); $stayOnPage = 0 if (not defined $stayOnPage); - if ($ENV{'browser.interface'} eq 'textual' || - $ENV{'environment.remote'} eq 'off' ) { + if ($env{'browser.interface'} eq 'textual' || + $env{'environment.remote'} eq 'off' ) { $stayOnPage=1; } $width = 350 if (not defined $width); @@ -833,6 +835,98 @@ ENDTEMPLATE =pod +=item * change_content_javascript(): + +This and the next function allow you to create small sections of an +otherwise static HTML page that you can update on the fly with +Javascript, even in Netscape 4. + +The Javascript fragment returned by this function (no E<lt>scriptE<gt> tag) +must be written to the HTML page once. It will prove the Javascript +function "change(name, content)". Calling the change function with the +name of the section +you want to update, matching the name passed to C<changable_area>, and +the new content you want to put in there, will put the content into +that area. + +B<Note>: Netscape 4 only reserves enough space for the changable area +to contain room for the original contents. You need to "make space" +for whatever changes you wish to make, and be B<sure> to check your +code in Netscape 4. This feature in Netscape 4 is B<not> powerful; +it's adequate for updating a one-line status display, but little more. +This script will set the space to 100% width, so you only need to +worry about height in Netscape 4. + +Modern browsers are much less limiting, and if you can commit to the +user not using Netscape 4, this feature may be used freely with +pretty much any HTML. + +=cut + +sub change_content_javascript { + # If we're on Netscape 4, we need to use Layer-based code + if ($env{'browser.type'} eq 'netscape' && + $env{'browser.version'} =~ /^4\./) { + return (<<NETSCAPE4); + function change(name, content) { + doc = document.layers[name+"___escape"].layers[0].document; + doc.open(); + doc.write(content); + doc.close(); + } +NETSCAPE4 + } else { + # Otherwise, we need to use semi-standards-compliant code + # (technically, "innerHTML" isn't standard but the equivalent + # is really scary, and every useful browser supports it + return (<<DOMBASED); + function change(name, content) { + element = document.getElementById(name); + element.innerHTML = content; + } +DOMBASED + } +} + +=pod + +=item * changable_area($name, $origContent): + +This provides a "changable area" that can be modified on the fly via +the Javascript code provided in C<change_content_javascript>. $name is +the name you will use to reference the area later; do not repeat the +same name on a given HTML page more then once. $origContent is what +the area will originally contain, which can be left blank. + +=cut + +sub changable_area { + my ($name, $origContent) = @_; + + if ($env{'browser.type'} eq 'netscape' && + $env{'browser.version'} =~ /^4\./) { + # If this is netscape 4, we need to use the Layer tag + return "<ilayer width='100%' id='${name}___escape' overflow='none'><layer width='100%' id='$name' overflow='none'>$origContent</layer></ilayer>"; + } else { + return "<span id='$name'>$origContent</span>"; + } +} + +=pod + +=back + +=head1 Excel and CSV file utility routines + +=over 4 + +=cut + +############################################################### +############################################################### + +=pod + =item * csv_translate($text) Translate $text to allow it to be output as a 'comma separated values' @@ -849,7 +943,6 @@ sub csv_translate { return $text; } - ############################################################### ############################################################### @@ -873,6 +966,10 @@ Currently supported formats: =item h3 +=item h4 + +=item i + =item date =back @@ -895,6 +992,7 @@ sub define_excel_formats { $format->{'h1'} = $workbook->add_format(bold=>1, size=>18); $format->{'h2'} = $workbook->add_format(bold=>1, size=>16); $format->{'h3'} = $workbook->add_format(bold=>1, size=>14); + $format->{'h4'} = $workbook->add_format(bold=>1, size=>12); $format->{'i'} = $workbook->add_format(italic=>1); $format->{'date'} = $workbook->add_format(num_format=> 'mm/dd/yyyy hh:mm:ss'); @@ -906,84 +1004,83 @@ sub define_excel_formats { =pod -=item * change_content_javascript(): - -This and the next function allow you to create small sections of an -otherwise static HTML page that you can update on the fly with -Javascript, even in Netscape 4. +=item * create_workbook -The Javascript fragment returned by this function (no E<lt>scriptE<gt> tag) -must be written to the HTML page once. It will prove the Javascript -function "change(name, content)". Calling the change function with the -name of the section -you want to update, matching the name passed to C<changable_area>, and -the new content you want to put in there, will put the content into -that area. +Create an Excel worksheet. If it fails, output message on the +request object and return undefs. -B<Note>: Netscape 4 only reserves enough space for the changable area -to contain room for the original contents. You need to "make space" -for whatever changes you wish to make, and be B<sure> to check your -code in Netscape 4. This feature in Netscape 4 is B<not> powerful; -it's adequate for updating a one-line status display, but little more. -This script will set the space to 100% width, so you only need to -worry about height in Netscape 4. +Inputs: Apache request object -Modern browsers are much less limiting, and if you can commit to the -user not using Netscape 4, this feature may be used freely with -pretty much any HTML. +Returns (undef) on failure, + Excel worksheet object, scalar with filename, and formats + from &Apache::loncommon::define_excel_formats on success =cut -sub change_content_javascript { - # If we're on Netscape 4, we need to use Layer-based code - if ($ENV{'browser.type'} eq 'netscape' && - $ENV{'browser.version'} =~ /^4\./) { - return (<<NETSCAPE4); - function change(name, content) { - doc = document.layers[name+"___escape"].layers[0].document; - doc.open(); - doc.write(content); - doc.close(); - } -NETSCAPE4 - } else { - # Otherwise, we need to use semi-standards-compliant code - # (technically, "innerHTML" isn't standard but the equivalent - # is really scary, and every useful browser supports it - return (<<DOMBASED); - function change(name, content) { - element = document.getElementById(name); - element.innerHTML = content; - } -DOMBASED +############################################################### +############################################################### +sub create_workbook { + my ($r) = @_; + # + # Create the excel spreadsheet + my $filename = '/prtspool/'. + $env{'user.name'}.'_'.$env{'user.domain'}.'_'. + time.'_'.rand(1000000000).'.xls'; + my $workbook = Spreadsheet::WriteExcel->new('/home/httpd'.$filename); + if (! defined($workbook)) { + $r->log_error("Error creating excel spreadsheet $filename: $!"); + $r->print('<p>'.&mt("Unable to create new Excel file. ". + "This error has been logged. ". + "Please alert your LON-CAPA administrator"). + '</p>'); + return (undef); } + # + $workbook->set_tempdir('/home/httpd/perl/tmp'); + # + my $format = &Apache::loncommon::define_excel_formats($workbook); + return ($workbook,$filename,$format); } +############################################################### +############################################################### + =pod -=item * changable_area($name, $origContent): +=item * create_text_file -This provides a "changable area" that can be modified on the fly via -the Javascript code provided in C<change_content_javascript>. $name is -the name you will use to reference the area later; do not repeat the -same name on a given HTML page more then once. $origContent is what -the area will originally contain, which can be left blank. +Create a file to write to and eventually make available to the usre. +If file creation fails, outputs an error message on the request object and +return undefs. -=cut +Inputs: Apache request object, and file suffix -sub changable_area { - my ($name, $origContent) = @_; +Returns (undef) on failure, + Filehandle and filename on success. - if ($ENV{'browser.type'} eq 'netscape' && - $ENV{'browser.version'} =~ /^4\./) { - # If this is netscape 4, we need to use the Layer tag - return "<ilayer width='100%' id='${name}___escape' overflow='none'><layer width='100%' id='$name' overflow='none'>$origContent</layer></ilayer>"; - } else { - return "<span id='$name'>$origContent</span>"; +=cut + +############################################################### +############################################################### +sub create_text_file { + my ($r,$suffix) = @_; + if (! defined($suffix)) { $suffix = 'txt'; }; + my $fh; + my $filename = '/prtspool/'. + $env{'user.name'}.'_'.$env{'user.domain'}.'_'. + time.'_'.rand(1000000000).'.'.$suffix; + $fh = Apache::File->new('>/home/httpd'.$filename); + if (! defined($fh)) { + $r->log_error("Couldn't open $filename for output $!"); + $r->print("Problems occured in creating the output file. ". + "This error has been logged. ". + "Please alert your LON-CAPA administrator."); } + return ($fh,$filename) } -=pod + +=pod =back @@ -1045,7 +1142,7 @@ sub multiple_select_form { $output.="\n<select name='$name' size='$size' multiple='1'>"; foreach (sort(keys(%hash))) { $output.='<option value="'.$_.'" '; - $output.='selected ' if ($selected{$_}); + $output.='selected="selected" ' if ($selected{$_}); $output.='>'.$hash{$_}."</option>\n"; } $output.="</select>\n"; @@ -1076,7 +1173,7 @@ sub select_form { } foreach (@keys) { $selectform.="<option value=\"$_\" ". - ($_ eq $def ? 'selected' : ''). + ($_ eq $def ? 'selected="selected" ' : ''). ">".&mt($hash{$_})."</option>\n"; } $selectform.="</select>"; @@ -1113,7 +1210,7 @@ sub select_level_form { my $selectform = "<select name=\"$name\" size=\"1\">\n"; for (my $i=0; $i<=18; $i++) { $selectform.="<option value=\"$i\" ". - ($i==$deflevel ? 'selected' : ''). + ($i==$deflevel ? 'selected="selected" ' : ''). ">".&gradeleveldescription($i)."</option>\n"; } $selectform.="</select>"; @@ -1143,7 +1240,7 @@ sub select_dom_form { my $selectdomain = "<select name=\"$name\" size=\"1\">\n"; foreach (@domains) { $selectdomain.="<option value=\"$_\" ". - ($_ eq $defdom ? 'selected="selected"' : ''). + ($_ eq $defdom ? 'selected="selected" ' : ''). ">$_</option>\n"; } $selectdomain.="</select>"; @@ -1807,13 +1904,13 @@ if the user does not sub nickname { my ($uname,$udom)=@_; my %names; - if ($uname eq $ENV{'user.name'} && - $udom eq $ENV{'user.domain'}) { - %names=('nickname' => $ENV{'environment.nickname'} , - 'firstname' => $ENV{'environment.firstname'} , - 'middlename' => $ENV{'environment.middlename'}, - 'lastname' => $ENV{'environment.lastname'} , - 'generation' => $ENV{'environment.generation'}); + if ($uname eq $env{'user.name'} && + $udom eq $env{'user.domain'}) { + %names=('nickname' => $env{'environment.nickname'} , + 'firstname' => $env{'environment.firstname'} , + 'middlename' => $env{'environment.middlename'}, + 'lastname' => $env{'environment.lastname'} , + 'generation' => $env{'environment.generation'}); } else { %names=&Apache::lonnet::get('environment', ['nickname','firstname','middlename', @@ -1844,8 +1941,8 @@ Gets a users screenname and returns it a sub screenname { my ($uname,$udom)=@_; - if ($uname eq $ENV{'user.name'} && - $udom eq $ENV{'user.domain'}) {return $ENV{'environment.screenname'};} + if ($uname eq $env{'user.name'} && + $udom eq $env{'user.domain'}) {return $env{'environment.screenname'};} my %names=&Apache::lonnet::get('environment',['screenname'],$udom,$uname); return $names{'screenname'}; } @@ -1903,8 +2000,6 @@ sub track_student_link { return qq{<a href="$link" title="$title" $target>$linktext</a>}; } - - =pod =back @@ -2093,8 +2188,8 @@ sub display_languages { $languages{$_}=1; } &get_unprocessed_cgi($ENV{'QUERY_STRING'},['displaylanguage']); - if ($ENV{'form.displaylanguage'}) { - foreach (split(/\s*(\,|\;|\:)\s*/,$ENV{'form.displaylanguage'})) { + if ($env{'form.displaylanguage'}) { + foreach (split(/\s*(\,|\;|\:)\s*/,$env{'form.displaylanguage'})) { $languages{$_}=1; } } @@ -2103,24 +2198,24 @@ sub display_languages { sub preferred_languages { my @languages=(); - if ($ENV{'course.'.$ENV{'request.course.id'}.'.languages'}) { + if ($env{'course.'.$env{'request.course.id'}.'.languages'}) { @languages=(@languages,split(/\s*(\,|\;|\:)\s*/, - $ENV{'course.'.$ENV{'request.course.id'}.'.languages'})); + $env{'course.'.$env{'request.course.id'}.'.languages'})); } - if ($ENV{'environment.languages'}) { - @languages=split(/\s*(\,|\;|\:)\s*/,$ENV{'environment.languages'}); + if ($env{'environment.languages'}) { + @languages=split(/\s*(\,|\;|\:)\s*/,$env{'environment.languages'}); } my $browser=(split(/\;/,$ENV{'HTTP_ACCEPT_LANGUAGE'}))[0]; if ($browser) { @languages=(@languages,split(/\s*(\,|\;|\:)\s*/,$browser)); } - if ($Apache::lonnet::domain_lang_def{$ENV{'user.domain'}}) { + if ($Apache::lonnet::domain_lang_def{$env{'user.domain'}}) { @languages=(@languages, - $Apache::lonnet::domain_lang_def{$ENV{'user.domain'}}); + $Apache::lonnet::domain_lang_def{$env{'user.domain'}}); } - if ($Apache::lonnet::domain_lang_def{$ENV{'request.role.domain'}}) { + if ($Apache::lonnet::domain_lang_def{$env{'request.role.domain'}}) { @languages=(@languages, - $Apache::lonnet::domain_lang_def{$ENV{'request.role.domain'}}); + $Apache::lonnet::domain_lang_def{$env{'request.role.domain'}}); } if ($Apache::lonnet::domain_lang_def{ $Apache::lonnet::perlvar{'lonDefDomain'}}) { @@ -2353,7 +2448,7 @@ sub submlink { &Apache::lonxml::whichuser($symb); if (!$symb) { $symb=$cursymb; } } - if (!$symb) { $symb=&symbread(); } + if (!$symb) { $symb=&Apache::lonnet::symbread(); } $symb=&Apache::lonnet::escape($symb); if ($target) { $target="target=\"$target\""; } return '<a href="/adm/grades?&command=submission&'. @@ -2399,7 +2494,7 @@ sub pprmlink { &Apache::lonxml::whichuser($symb); if (!$symb) { $symb=$cursymb; } } - if (!$symb) { $symb=&symbread(); } + if (!$symb) { $symb=&Apache::lonnet::symbread(); } $symb=&Apache::lonnet::escape($symb); if ($target) { $target="target=\"$target\""; } return '<a href="/adm/parmset?&command=set&'. @@ -2442,9 +2537,9 @@ sub maketime { sub findallcourses { my %courses=(); my $now=time; - foreach (keys %ENV) { + foreach (keys %env) { if ($_=~/^user\.role\.\w+\.\/(\w+)\/(\w+)/) { - my ($starttime,$endtime)=$ENV{$_}; + my ($starttime,$endtime)=$env{$_}; my $active=1; if ($starttime) { if ($now<$starttime) { $active=0; } @@ -2481,9 +2576,9 @@ sub determinedomain { if (! $domain) { # Determine domain if we have not been given one $domain = $Apache::lonnet::perlvar{'lonDefDomain'}; - if ($ENV{'user.domain'}) { $domain=$ENV{'user.domain'}; } - if ($ENV{'request.role.domain'}) { - $domain=$ENV{'request.role.domain'}; + if ($env{'user.domain'}) { $domain=$env{'user.domain'}; } + if ($env{'request.role.domain'}) { + $domain=$env{'request.role.domain'}; } } return $domain; @@ -2528,7 +2623,7 @@ Returns: value of designparamter $which ############################################## sub designparm { my ($which,$domain)=@_; - if ($ENV{'browser.blackwhite'} eq 'on') { + if ($env{'browser.blackwhite'} eq 'on') { if ($which=~/\.(font|alink|vlink|link)$/) { return '#000000'; } @@ -2539,8 +2634,8 @@ sub designparm { return '#CCCCCC'; } } - if ($ENV{'environment.color.'.$which}) { - return $ENV{'environment.color.'.$which}; + if ($env{'environment.color.'.$which}) { + return $env{'environment.color.'.$which}; } $domain=&determinedomain($domain); if ($designhash{$domain.'.'.$which}) { @@ -2606,16 +2701,16 @@ sub bodytag { # Accessibility font enhance unless ($addentries) { $addentries=''; } my $addstyle=''; - if ($ENV{'browser.fontenhance'} eq 'on') { + if ($env{'browser.fontenhance'} eq 'on') { $addstyle=' font-size: x-large;'; } # role and realm my ($role,$realm) - =&Apache::lonnet::plaintext((split(/\./,$ENV{'request.role'}))[0]); + =&Apache::lonnet::plaintext((split(/\./,$env{'request.role'}))[0]); # realm - if ($ENV{'request.course.id'}) { + if ($env{'request.course.id'}) { $realm= - $ENV{'course.'.$ENV{'request.course.id'}.'.description'}; + $env{'course.'.$env{'request.course.id'}.'.description'}; } unless ($realm) { $realm=' '; } # Set messages @@ -2632,25 +2727,32 @@ a:focus { color: red; background: yellow <body bgcolor="$pgbg" text="$font" alink="$alink" vlink="$vlink" link="$link" style="margin-top: 0px;$addstyle" $addentries> END + if ($env{'environment.texengine'} eq 'jsMath') { + $bodytag.='<script type="text/javascript"> + function NoFontMessage () {} + </script>'."\n". + '<script src="/adm/jsMath/jsMath.js"></script>'."\n"; + } + my $upperleft='<img src="http://'.$ENV{'HTTP_HOST'}.':'. $lonhttpdPort.$img.'" alt="'.$function.'" />'; if ($bodyonly) { return $bodytag; - } elsif ($ENV{'browser.interface'} eq 'textual') { + } elsif ($env{'browser.interface'} eq 'textual') { # Accessibility return $bodytag.&Apache::lonmenu::menubuttons($forcereg,'web', $forcereg). '<h1>LON-CAPA: '.$title.'</h1>'; - } elsif ($ENV{'environment.remote'} eq 'off') { + } elsif ($env{'environment.remote'} eq 'off') { # No Remote my $roleinfo=(<<ENDROLE); <td bgcolor="$tabbg" align="right"> <font size="2" face="Arial, Helvetica, sans-serif"> - $ENV{'environment.firstname'} - $ENV{'environment.middlename'} - $ENV{'environment.lastname'} - $ENV{'environment.generation'} + $env{'environment.firstname'} + $env{'environment.middlename'} + $env{'environment.lastname'} + $env{'environment.generation'} </font> <br /> <font size="2" face="Arial, Helvetica, sans-serif">$role</font> @@ -2664,9 +2766,9 @@ ENDROLE $titleinfo = $customtitle; } - if ($ENV{'request.state'} eq 'construct') { + if ($env{'request.state'} eq 'construct') { my ($uname,$thisdisfn)= - ($ENV{'request.filename'} =~ m|^/home/([^/]+)/public_html/(.*)|); + ($env{'request.filename'} =~ m|^/home/([^/]+)/public_html/(.*)|); my $formaction='/priv/'.$uname.'/'.$thisdisfn; $formaction=~s/\/+/\//g; unless ($customtitle) { #this is for resources; directories have customtitle, and crumbs and select recent are created in lonpubdir.pm @@ -2694,7 +2796,7 @@ ENDROLE 'cellspacing="3" cellpadding="3">'. '<tr><td rowspan="3" bgcolor="'.$tabbg.'">'. $titleinfo.'</td>'.$roleinfo.'</tr></table>'; - if ($ENV{'request.state'} eq 'construct') { + if ($env{'request.state'} eq 'construct') { $bodytag .= &Apache::lonmenu::menubuttons($forcereg,'web',$forcereg,$titletable); } else { $bodytag .= &Apache::lonmenu::menubuttons($forcereg,'web',$forcereg). @@ -2713,11 +2815,11 @@ ENDROLE # # Extra info if you are the DC my $dc_info = ''; - if ($ENV{'user.adv'} && exists($ENV{'user.role.dc./'. - $ENV{'course.'.$ENV{'request.course.id'}. + if ($env{'user.adv'} && exists($env{'user.role.dc./'. + $env{'course.'.$env{'request.course.id'}. '.domain'}.'/'})) { - my $cid = $ENV{'request.course.id'}; - $dc_info.= $cid.' '.$ENV{'course.'.$cid.'.internal.coursecode'}; + my $cid = $env{'request.course.id'}; + $dc_info.= $cid.' '.$env{'course.'.$cid.'.internal.coursecode'}; $dc_info = '('.$dc_info.')'; } # @@ -2731,12 +2833,12 @@ $upperleft</td> <tr> <td rowspan="3" bgcolor="$tabbg"> $titleinfo $dc_info -<td bgcolor="$tabbg" align="right"> +</td><td bgcolor="$tabbg" align="right"> <font size="2" face="Arial, Helvetica, sans-serif"> - $ENV{'environment.firstname'} - $ENV{'environment.middlename'} - $ENV{'environment.lastname'} - $ENV{'environment.generation'} + $env{'environment.firstname'} + $env{'environment.middlename'} + $env{'environment.lastname'} + $env{'environment.generation'} </font> </td> </tr> @@ -2750,6 +2852,40 @@ ENDBODY } ############################################### +############################################### + +=pod + +=back + +=head1 HTTP Helpers + +=over 4 + +=item * &endbodytag() + +Returns a uniform footer for LON-CAPA web pages. + +Inputs: + +=over 4 + +=back + +Returns: A uniform footer for LON-CAPA web pages. + +=cut + +sub endbodytag { + my $endbodytag='</body>'; + if ($env{'environment.texengine'} eq 'jsMath') { + $endbodytag='<script type="text/javascript">jsMath.Process()</script>'. + "\n".$endbodytag; + } + return $endbodytag; +} + +############################################### =pod @@ -2763,13 +2899,13 @@ Returns either 'student','coordinator',' ############################################### sub get_users_function { my $function = 'student'; - if ($ENV{'request.role'}=~/^(cc|in|ta|ep)/) { + if ($env{'request.role'}=~/^(cc|in|ta|ep)/) { $function='coordinator'; } - if ($ENV{'request.role'}=~/^(su|dc|ad|li)/) { + if ($env{'request.role'}=~/^(su|dc|ad|li)/) { $function='admin'; } - if (($ENV{'request.role'}=~/^(au|ca)/) || + if (($env{'request.role'}=~/^(au|ca)/) || ($ENV{'REQUEST_URI'}=~/^(\/priv|\~)/)) { $function='author'; } @@ -2837,8 +2973,9 @@ sub get_posted_cgi { my $r=shift; my $buffer; - - $r->read($buffer,$r->header_in('Content-length'),0); + if ($r->header_in('Content-length')) { + $r->read($buffer,$r->header_in('Content-length'),0); + } unless ($buffer=~/^(\-+\w+)\s+Content\-Disposition\:\s*form\-data/si) { my @pairs=split(/&/,$buffer); my $pair; @@ -2863,8 +3000,8 @@ sub get_posted_cgi { if ($name) { chomp($value); if ($fname) { - $ENV{"form.$name.filename"}=$fname; - $ENV{"form.$name.mimetype"}=$fmime; + $env{"form.$name.filename"}=$fname; + $env{"form.$name.mimetype"}=$fmime; } else { $value=~s/\s+$//s; } @@ -2896,7 +3033,7 @@ sub get_posted_cgi { } } } - $ENV{'request.method'}=$ENV{'REQUEST_METHOD'}; + $env{'request.method'}=$ENV{'REQUEST_METHOD'}; $r->method_number(M_GET); $r->method('GET'); $r->headers_in->unset('Content-length'); @@ -2906,14 +3043,14 @@ sub get_posted_cgi { =item * get_unprocessed_cgi($query,$possible_names) -Modify the %ENV hash to contain unprocessed CGI form parameters held in +Modify the %env hash to contain unprocessed CGI form parameters held in $query. The parameters listed in $possible_names (an array reference), -will be set in $ENV{'form.name'} if they do not already exist. +will be set in $env{'form.name'} if they do not already exist. Typically called with $ENV{'QUERY_STRING'} as the first parameter. $possible_names is an ref to an array of form element names. As an example: get_unprocessed_cgi($ENV{'QUERY_STRING'},['uname','udom']); -will result in $ENV{'form.uname'} and $ENV{'form.udom'} being set. +will result in $env{'form.uname'} and $env{'form.udom'} being set. =cut @@ -2927,7 +3064,7 @@ sub get_unprocessed_cgi { $value =~ tr/+/ /; $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg; &Apache::lonxml::debug("Seting :$name: to :$value:"); - unless (defined($ENV{'form.'.$name})) { &add_to_env('form.'.$name,$value) }; + unless (defined($env{'form.'.$name})) { &add_to_env('form.'.$name,$value) }; } } } @@ -2941,7 +3078,7 @@ returns cache-controlling header code =cut sub cacheheader { - unless ($ENV{'request.method'} eq 'GET') { return ''; } + unless ($env{'request.method'} eq 'GET') { return ''; } my $date=strftime("%a, %d %b %Y %H:%M:%S GMT",gmtime); my $output .='<meta HTTP-EQUIV="Expires" CONTENT="'.$date.'" /> <meta HTTP-EQUIV="Cache-control" CONTENT="no-cache" /> @@ -2960,7 +3097,7 @@ specifies header code to not have cache sub no_cache { my ($r) = @_; if ($ENV{'REQUEST_METHOD'} ne 'GET' && - $ENV{'request.method'} ne 'GET') { return ''; } + $env{'request.method'} ne 'GET') { return ''; } my $date=strftime("%a, %d %b %Y %H:%M:%S GMT",gmtime(time)); $r->no_cache(1); $r->header_out("Expires" => $date); @@ -2969,6 +3106,7 @@ sub no_cache { sub content_type { my ($r,$type,$charset) = @_; + if ($env{'browser.mathml'} && $type eq 'text/html') { $type='text/xml'; } unless ($charset) { $charset=&Apache::lonlocal::current_encoding; } @@ -2984,7 +3122,7 @@ sub content_type { =item * add_to_env($name,$value) -adds $name to the %ENV hash with value +adds $name to the %env hash with value $value, if $name already exists, the entry is converted to an array reference and $value is added to the array. @@ -2992,18 +3130,18 @@ reference and $value is added to the arr sub add_to_env { my ($name,$value)=@_; - if (defined($ENV{$name})) { - if (ref($ENV{$name})) { + if (defined($env{$name})) { + if (ref($env{$name})) { #already have multiple values - push(@{ $ENV{$name} },$value); + push(@{ $env{$name} },$value); } else { #first time seeing multiple values, convert hash entry to an arrayref - my $first=$ENV{$name}; - undef($ENV{$name}); - push(@{ $ENV{$name} },$first,$value); + my $first=$env{$name}; + undef($env{$name}); + push(@{ $env{$name} },$first,$value); } } else { - $ENV{$name}=$value; + $env{$name}=$value; } } @@ -3011,7 +3149,7 @@ sub add_to_env { =item * get_env_multiple($name) -gets $name from the %ENV hash, it seemlessly handles the cases where multiple +gets $name from the %env hash, it seemlessly handles the cases where multiple values may be defined and end up as an array ref. returns an array of values @@ -3021,12 +3159,12 @@ returns an array of values sub get_env_multiple { my ($name) = @_; my @values; - if (defined($ENV{$name})) { + if (defined($env{$name})) { # exists is it an array - if (ref($ENV{$name})) { - @values=@{ $ENV{$name} }; + if (ref($env{$name})) { + @values=@{ $env{$name} }; } else { - $values[0]=$ENV{$name}; + $values[0]=$env{$name}; } } return(@values); @@ -3044,25 +3182,25 @@ sub get_env_multiple { =item * upfile_store($r) Store uploaded file, $r should be the HTTP Request object, -needs $ENV{'form.upfile'} +needs $env{'form.upfile'} returns $datatoken to be put into hidden field =cut sub upfile_store { my $r=shift; - $ENV{'form.upfile'}=~s/\r/\n/gs; - $ENV{'form.upfile'}=~s/\f/\n/gs; - $ENV{'form.upfile'}=~s/\n+/\n/gs; - $ENV{'form.upfile'}=~s/\n+$//gs; + $env{'form.upfile'}=~s/\r/\n/gs; + $env{'form.upfile'}=~s/\f/\n/gs; + $env{'form.upfile'}=~s/\n+/\n/gs; + $env{'form.upfile'}=~s/\n+$//gs; - my $datatoken=$ENV{'user.name'}.'_'.$ENV{'user.domain'}. - '_enroll_'.$ENV{'request.course.id'}.'_'.time.'_'.$$; + my $datatoken=$env{'user.name'}.'_'.$env{'user.domain'}. + '_enroll_'.$env{'request.course.id'}.'_'.time.'_'.$$; { my $datafile = $r->dir_config('lonDaemons'). '/tmp/'.$datatoken.'.tmp'; if ( open(my $fh,">$datafile") ) { - print $fh $ENV{'form.upfile'}; + print $fh $env{'form.upfile'}; close($fh); } } @@ -3074,8 +3212,8 @@ sub upfile_store { =item * load_tmp_file($r) Load uploaded file from tmp, $r should be the HTTP Request object, -needs $ENV{'form.datatoken'}, -sets $ENV{'form.upfile'} to the contents of the file +needs $env{'form.datatoken'}, +sets $env{'form.upfile'} to the contents of the file =cut @@ -3084,13 +3222,13 @@ sub load_tmp_file { my @studentdata=(); { my $studentfile = $r->dir_config('lonDaemons'). - '/tmp/'.$ENV{'form.datatoken'}.'.tmp'; + '/tmp/'.$env{'form.datatoken'}.'.tmp'; if ( open(my $fh,"<$studentfile") ) { @studentdata=<$fh>; close($fh); } } - $ENV{'form.upfile'}=join('',@studentdata); + $env{'form.upfile'}=join('',@studentdata); } =pod @@ -3099,15 +3237,15 @@ sub load_tmp_file { Separate uploaded file into records returns array of records, -needs $ENV{'form.upfile'} and $ENV{'form.upfiletype'} +needs $env{'form.upfile'} and $env{'form.upfiletype'} =cut sub upfile_record_sep { - if ($ENV{'form.upfiletype'} eq 'xml') { + if ($env{'form.upfiletype'} eq 'xml') { } else { my @records; - foreach my $line (split(/\n/,$ENV{'form.upfile'})) { + foreach my $line (split(/\n/,$env{'form.upfile'})) { if ($line=~/^\s*$/) { next; } push(@records,$line); } @@ -3119,30 +3257,35 @@ sub upfile_record_sep { =item * record_sep($record) -Separate a record into fields $record should be an item from the upfile_record_sep(), needs $ENV{'form.upfiletype'} +Separate a record into fields $record should be an item from the upfile_record_sep(), needs $env{'form.upfiletype'} =cut +sub takeleft { + my $index=shift; + return substr('0000'.$index,-4,4); +} + sub record_sep { my $record=shift; my %components=(); - if ($ENV{'form.upfiletype'} eq 'xml') { - } elsif ($ENV{'form.upfiletype'} eq 'space') { + if ($env{'form.upfiletype'} eq 'xml') { + } elsif ($env{'form.upfiletype'} eq 'space') { my $i=0; foreach (split(/\s+/,$record)) { my $field=$_; $field=~s/^(\"|\')//; $field=~s/(\"|\')$//; - $components{$i}=$field; + $components{&takeleft($i)}=$field; $i++; } - } elsif ($ENV{'form.upfiletype'} eq 'tab') { + } elsif ($env{'form.upfiletype'} eq 'tab') { my $i=0; foreach (split(/\t/,$record)) { my $field=$_; $field=~s/^(\"|\')//; $field=~s/(\"|\')$//; - $components{$i}=$field; + $components{&takeleft($i)}=$field; $i++; } } else { @@ -3160,7 +3303,7 @@ sub record_sep { $field=~s/^\s*$delimiter//; $field=~s/$delimiter\s*$//; } - $components{$i}=$field; + $components{&takeleft($i)}=$field; $i++; } } @@ -3269,7 +3412,7 @@ sub csv_print_select_table { $r->print('<option value="none"></option>'); foreach (sort({$a <=> $b} keys(%sone))) { $r->print('<option value="'.$_.'"'. - ($_ eq $defaultcol ? ' selected ' : ''). + ($_ eq $defaultcol ? ' selected="selected" ' : ''). '>Column '.($_+1).'</option>'); } $r->print('</select></td></tr>'."\n"); @@ -3313,13 +3456,13 @@ sub csv_samples_select_table { foreach (@$d) { my ($value,$display,$defaultcol)=@{ $_ }; $r->print('<option value="'.$value.'"'. - ($i eq $defaultcol ? ' selected ':'').'>'. + ($i eq $defaultcol ? ' selected="selected" ':'').'>'. $display.'</option>'); } $r->print('</select></td><td>'); - if (defined($sone{$_})) { $r->print($sone{$_}."</br>\n"); } - if (defined($stwo{$_})) { $r->print($stwo{$_}."</br>\n"); } - if (defined($sthree{$_})) { $r->print($sthree{$_}."</br>\n"); } + if (defined($sone{$_})) { $r->print($sone{$_}."<br />\n"); } + if (defined($stwo{$_})) { $r->print($stwo{$_}."<br />\n"); } + if (defined($sthree{$_})) { $r->print($sthree{$_}."<br />\n"); } $r->print('</td></tr>'); $i++; } @@ -3827,34 +3970,34 @@ Returns: both routines return nothing sub store_course_settings { # save to the environment # appenv the same items, just to be safe - my $courseid = $ENV{'request.course.id'}; - my $coursedom = $ENV{'course.'.$courseid.'.domain'}; + my $courseid = $env{'request.course.id'}; + my $coursedom = $env{'course.'.$courseid.'.domain'}; my ($prefix,$Settings) = @_; my %SaveHash; my %AppHash; while (my ($setting,$type) = each(%$Settings)) { my $basename = 'internal.'.$prefix.'.'.$setting; my $envname = 'course.'.$courseid.'.'.$basename; - if (exists($ENV{'form.'.$setting})) { + if (exists($env{'form.'.$setting})) { # Save this value away if ($type eq 'scalar' && - (! exists($ENV{$envname}) || - $ENV{$envname} ne $ENV{'form.'.$setting})) { - $SaveHash{$basename} = $ENV{'form.'.$setting}; - $AppHash{$envname} = $ENV{'form.'.$setting}; + (! exists($env{$envname}) || + $env{$envname} ne $env{'form.'.$setting})) { + $SaveHash{$basename} = $env{'form.'.$setting}; + $AppHash{$envname} = $env{'form.'.$setting}; } elsif ($type eq 'array') { my $stored_form; - if (ref($ENV{'form.'.$setting})) { + if (ref($env{'form.'.$setting})) { $stored_form = join(',', map { &Apache::lonnet::escape($_); - } sort(@{$ENV{'form.'.$setting}})); + } sort(@{$env{'form.'.$setting}})); } else { $stored_form = - &Apache::lonnet::escape($ENV{'form.'.$setting}); + &Apache::lonnet::escape($env{'form.'.$setting}); } # Determine if the array contents are the same. - if ($stored_form ne $ENV{$envname}) { + if ($stored_form ne $env{$envname}) { $SaveHash{$basename} = $stored_form; $AppHash{$envname} = $stored_form; } @@ -3863,7 +4006,7 @@ sub store_course_settings { } my $put_result = &Apache::lonnet::put('environment',\%SaveHash, $coursedom, - $ENV{'course.'.$courseid.'.num'}); + $env{'course.'.$courseid.'.num'}); if ($put_result !~ /^(ok|delayed)/) { &Apache::lonnet::logthis('unable to save form parameters, '. 'got error:'.$put_result); @@ -3874,20 +4017,20 @@ sub store_course_settings { } sub restore_course_settings { - my $courseid = $ENV{'request.course.id'}; + my $courseid = $env{'request.course.id'}; my ($prefix,$Settings) = @_; while (my ($setting,$type) = each(%$Settings)) { - next if (exists($ENV{'form.'.$setting})); + next if (exists($env{'form.'.$setting})); my $envname = 'course.'.$courseid.'.internal.'.$prefix. '.'.$setting; - if (exists($ENV{$envname})) { + if (exists($env{$envname})) { if ($type eq 'scalar') { - $ENV{'form.'.$setting} = $ENV{$envname}; + $env{'form.'.$setting} = $env{$envname}; } elsif ($type eq 'array') { - $ENV{'form.'.$setting} = [ + $env{'form.'.$setting} = [ map { &Apache::lonnet::unescape($_); - } split(',',$ENV{$envname}) + } split(',',$env{$envname}) ]; } }