--- loncom/interface/loncommon.pm 2004/11/02 20:48:02 1.226
+++ loncom/interface/loncommon.pm 2005/06/30 17:56:28 1.268
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# a pile of common routines
#
-# $Id: loncommon.pm,v 1.226 2004/11/02 20:48:02 albertel Exp $
+# $Id: loncommon.pm,v 1.268 2005/06/30 17:56:28 albertel 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');
@@ -722,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);
@@ -767,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);
@@ -815,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 EscriptE 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, and
+the new content you want to put in there, will put the content into
+that area.
+
+B: 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 to check your
+code in Netscape 4. This feature in Netscape 4 is B 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 (<. $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 "$origContent";
+ } else {
+ return "$origContent";
+ }
+}
+
+=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'
@@ -831,7 +943,6 @@ sub csv_translate {
return $text;
}
-
###############################################################
###############################################################
@@ -855,6 +966,10 @@ Currently supported formats:
=item h3
+=item h4
+
+=item i
+
=item date
=back
@@ -877,6 +992,8 @@ 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');
return $format;
@@ -887,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 EscriptE 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, 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: 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 to check your
-code in Netscape 4. This feature in Netscape 4 is B 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 (<new('/home/httpd'.$filename);
+ if (! defined($workbook)) {
+ $r->log_error("Error creating excel spreadsheet $filename: $!");
+ $r->print('
'.&mt("Unable to create new Excel file. ".
+ "This error has been logged. ".
+ "Please alert your LON-CAPA administrator").
+ '
');
+ 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. $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 "$origContent";
- } else {
- return "$origContent";
+=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
@@ -1026,7 +1142,7 @@ sub multiple_select_form {
$output.="\n\n";
@@ -1057,7 +1173,7 @@ sub select_form {
}
foreach (@keys) {
$selectform.="\n";
}
$selectform.="";
@@ -1094,7 +1210,7 @@ sub select_level_form {
my $selectform = "";
@@ -1124,7 +1240,7 @@ sub select_dom_form {
my $selectdomain = "";
@@ -1223,9 +1339,11 @@ Outputs:
###############################################################
###############################################################
sub decode_user_agent {
+ my ($r)=@_;
my @browsertype=split(/\&/,$Apache::lonnet::perlvar{"lonBrowsDet"});
my %mathcap=split(/\&/,$$Apache::lonnet::perlvar{"lonMathML"});
my $httpbrowser=$ENV{"HTTP_USER_AGENT"};
+ if (!$httpbrowser && $r) { $httpbrowser=$r->header_in('User-Agent'); }
my $clientbrowser='unknown';
my $clientversion='0';
my $clientmathml='';
@@ -1786,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',
@@ -1823,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'};
}
@@ -1866,24 +1984,23 @@ sub syllabuswrapper {
}
sub track_student_link {
- my ($linktext,$sname,$sdom,$target) = @_;
- my $link ="/adm/trackstudent";
+ my ($linktext,$sname,$sdom,$target,$start) = @_;
+ my $link ="/adm/trackstudent?";
my $title = 'View recent activity';
if (defined($sname) && $sname !~ /^\s*$/ &&
defined($sdom) && $sdom !~ /^\s*$/) {
- $link .= "?selected_student=$sname:$sdom";
+ $link .= "selected_student=$sname:$sdom";
$title .= ' of this student';
- }
+ }
if (defined($target) && $target !~ /^\s*$/) {
$target = qq{target="$target"};
} else {
$target = '';
}
+ if ($start) { $link.='&start='.$start; }
return qq{$linktext};
}
-
-
=pod
=back
@@ -2072,8 +2189,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;
}
}
@@ -2082,24 +2199,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'}}) {
@@ -2278,7 +2395,7 @@ sub get_student_view {
if (defined($moreenv)) {
%form=(%form,%{$moreenv});
}
- if ($target eq 'tex') {$form{'grade_target'} = 'tex';}
+ if (defined($target)) { $form{'grade_target'} = $target; }
$feedurl=&Apache::lonnet::clutter($feedurl);
my $userview=&Apache::lonnet::ssi_body($feedurl,%form);
$userview=~s/\]*\>//gi;
@@ -2318,7 +2435,7 @@ sub get_student_answers {
=item * &submlink()
-Inputs: $text $uname $udom $symb
+Inputs: $text $uname $udom $symb $target
Returns: A link to grades.pm such as to see the SUBM view of a student
@@ -2326,15 +2443,64 @@ Returns: A link to grades.pm such as to
###############################################
sub submlink {
- my ($text,$uname,$udom,$symb)=@_;
+ my ($text,$uname,$udom,$symb,$target)=@_;
+ if (!($uname && $udom)) {
+ (my $cursymb, my $courseid,$udom,$uname)=
+ &Apache::lonxml::whichuser($symb);
+ if (!$symb) { $symb=$cursymb; }
+ }
+ if (!$symb) { $symb=&Apache::lonnet::symbread(); }
+ $symb=&Apache::lonnet::escape($symb);
+ if ($target) { $target="target=\"$target\""; }
+ return ''.$text.'';
+}
+##############################################
+
+=pod
+
+=item * &pgrdlink()
+
+Inputs: $text $uname $udom $symb $target
+
+Returns: A link to grades.pm such as to see the PGRD view of a student
+
+=cut
+
+###############################################
+sub pgrdlink {
+ my $link=&submlink(@_);
+ $link=~s/(&command=submission)/$1&showgrading=yes/;
+ return $link;
+}
+##############################################
+
+=pod
+
+=item * &pprmlink()
+
+Inputs: $text $uname $udom $symb $target
+
+Returns: A link to parmset.pm such as to see the PPRM view of a
+student andn resource
+
+=cut
+
+###############################################
+sub pprmlink {
+ my ($text,$uname,$udom,$symb,$target)=@_;
if (!($uname && $udom)) {
(my $cursymb, my $courseid,$udom,$uname)=
&Apache::lonxml::whichuser($symb);
if (!$symb) { $symb=$cursymb; }
}
- if (!$symb) { $symb=&symbread(); }
- return ''.$text.'';
+ if (!$symb) { $symb=&Apache::lonnet::symbread(); }
+ $symb=&Apache::lonnet::escape($symb);
+ if ($target) { $target="target=\"$target\""; }
+ return ''.$text.'';
}
##############################################
@@ -2372,9 +2538,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; }
@@ -2411,9 +2577,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;
@@ -2458,7 +2624,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';
}
@@ -2469,8 +2635,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}) {
@@ -2536,16 +2702,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
@@ -2555,49 +2721,89 @@ sub bodytag {
if (!defined($lonhttpdPort)) { $lonhttpdPort='8080'; }
# construct main body tag
my $bodytag = <
+
END
+ if ($env{'environment.texengine'} eq 'jsMath') {
+ $bodytag.=''."\n".
+ ''."\n";
+ }
+
my $upperleft='';
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).
'
@@ -2636,6 +2853,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='';
+ if ($env{'environment.texengine'} eq 'jsMath') {
+ $endbodytag=''.
+ "\n".$endbodytag;
+ }
+ return $endbodytag;
+}
+
+###############################################
=pod
@@ -2649,13 +2900,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';
}
@@ -2664,12 +2915,68 @@ sub get_users_function {
###############################################
+=pod
+
+=item get_sections
+
+Determines all the sections for a course including
+sections with students and sections containing other roles.
+Incoming parameters: domain, course number, reference to
+section hash (keys to be section/group IDs), reference to
+array containing roles for which sections should be gathered
+(optional). If the fourth argument is undefined, sections
+are gathered for any role.
+
+Returns number of sections.
+
+=cut
+
+###############################################
+sub get_sections {
+ my ($cdom,$cnum,$sectioncount,$possible_roles) = @_;
+ if (!($cdom && $cnum)) { return 0; }
+ my $cid = $cdom.'_'.$cnum;
+ my $numsections = 0;
+
+ if (!defined($possible_roles) || (grep/^st$/,@$possible_roles)) {
+ my ($classlist) = &Apache::loncoursedata::get_classlist($cid,$cdom,$cnum);
+ my $sec_index = &Apache::loncoursedata::CL_SECTION();
+ my $status_index = &Apache::loncoursedata::CL_STATUS();
+ while (my ($student,$data) = each %$classlist) {
+ my ($section,$status) = ($data->[$sec_index],
+ $data->[$status_index]);
+ unless ($section eq '-1' || $section =~ /^\s*$/) {
+ if (!defined($$sectioncount{$section})) { $numsections++; }
+ $$sectioncount{$section}++;
+ }
+ }
+ }
+ my %courseroles = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum);
+ foreach my $user (sort(keys(%courseroles))) {
+ if ($user !~ /^(\w{2})/) { next; }
+ my ($role) = ($user =~ /^(\w{2})/);
+ if ($possible_roles && !(grep(/^$role$/,@$possible_roles))) { next; }
+ my $section;
+ if ($role eq 'cr' &&
+ $user =~ m-^$role/[^/]*/[^/]*/[^/]*:[^:]*:[^:]*:(\w+)-) {
+ $section=$1;
+ }
+ if ($user =~ /^$role:[^:]*:[^:]*:(\w+)/) { $section=$1; }
+ if (!defined($section) || $section eq '-1') { next; }
+ if (!defined($$sectioncount{$section})) { $numsections++; }
+ $$sectioncount{$section}++;
+ }
+ return $numsections;
+}
+
+
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;
@@ -2694,8 +3001,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;
}
@@ -2727,7 +3034,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');
@@ -2737,14 +3044,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
@@ -2758,7 +3065,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) };
}
}
}
@@ -2772,7 +3079,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 .='
@@ -2791,7 +3098,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);
@@ -2800,6 +3107,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;
}
@@ -2815,7 +3123,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.
@@ -2823,18 +3131,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;
}
}
@@ -2842,7 +3150,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
@@ -2852,12 +3160,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);
@@ -2875,25 +3183,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);
}
}
@@ -2905,8 +3213,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
@@ -2915,13 +3223,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
@@ -2930,14 +3238,19 @@ 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 {
- return split(/\n/,$ENV{'form.upfile'});
+ my @records;
+ foreach my $line (split(/\n/,$env{'form.upfile'})) {
+ if ($line=~/^\s*$/) { next; }
+ push(@records,$line);
+ }
+ return @records;
}
}
@@ -2945,30 +3258,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 {
@@ -2986,7 +3304,7 @@ sub record_sep {
$field=~s/^\s*$delimiter//;
$field=~s/$delimiter\s*$//;
}
- $components{$i}=$field;
+ $components{&takeleft($i)}=$field;
$i++;
}
}
@@ -3095,7 +3413,7 @@ sub csv_print_select_table {
$r->print('');
foreach (sort({$a <=> $b} keys(%sone))) {
$r->print('');
}
$r->print(''."\n");
@@ -3139,13 +3457,13 @@ sub csv_samples_select_table {
foreach (@$d) {
my ($value,$display,$defaultcol)=@{ $_ };
$r->print('');
}
$r->print('
');
- if (defined($sone{$_})) { $r->print($sone{$_}."\n"); }
- if (defined($stwo{$_})) { $r->print($stwo{$_}."\n"); }
- if (defined($sthree{$_})) { $r->print($sthree{$_}."\n"); }
+ if (defined($sone{$_})) { $r->print($sone{$_}." \n"); }
+ if (defined($stwo{$_})) { $r->print($stwo{$_}." \n"); }
+ if (defined($sthree{$_})) { $r->print($sthree{$_}." \n"); }
$r->print('
');
$i++;
}
@@ -3270,6 +3588,9 @@ they are plotted. If undefined, default
=item @Values: An array of array references. Each array reference holds data
to be plotted in a stacked bar chart.
+=item If the final element of @Values is a hash reference the key/value
+pairs will be added to the graph definition.
+
=back
Returns:
@@ -3290,6 +3611,10 @@ sub DrawBarGraph {
'#66ccff', '#ff9999', '#cccc33', '#660000', '#33cc66',
];
}
+ my $extra_settings = {};
+ if (ref($Values[-1]) eq 'HASH') {
+ $extra_settings = pop(@Values);
+ }
#
my $identifier = &get_cgi_id();
my $id = 'cgi.'.$identifier;
@@ -3365,6 +3690,11 @@ sub DrawBarGraph {
$ValuesHash{$id.'.bar_width'} = $bar_width;
$ValuesHash{$id.'.labels'} = join(',',@Labels);
#
+ # Deal with other parameters
+ while (my ($key,$value) = each(%$extra_settings)) {
+ $ValuesHash{$id.'.'.$key} = $value;
+ }
+ #
&Apache::lonnet::appenv(%ValuesHash);
return '';
}
@@ -3641,34 +3971,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;
}
@@ -3677,7 +4007,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);
@@ -3688,20 +4018,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})
];
}
}
@@ -3734,7 +4064,7 @@ sub icon {
$curfext.".gif";
}
}
- return $iconname;
+ return &lonhttpdurl($iconname);
}
sub lonhttpdurl {
@@ -3772,7 +4102,7 @@ sub escape_double {
# Escapes the last element of a full URL.
sub escape_url {
my ($url) = @_;
- my @urlslices = split(/\//, $url);
+ my @urlslices = split(/\//, $url,-1);
my $lastitem = &Apache::lonnet::escape(pop(@urlslices));
return join('/',@urlslices).'/'.$lastitem;
}