--- loncom/interface/loncommon.pm 2003/02/13 23:02:42 1.81 +++ loncom/interface/loncommon.pm 2008/05/19 17:00:22 1.653 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # a pile of common routines # -# $Id: loncommon.pm,v 1.81 2003/02/13 23:02:42 albertel Exp $ +# $Id: loncommon.pm,v 1.653 2008/05/19 17:00:22 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -25,13 +25,6 @@ # # http://www.lon-capa.org/ # -# YEAR=2001 -# 2/13-12/7 Guy Albertelli -# 12/21 Gerd Kortemeyer -# 12/25,12/28 Gerd Kortemeyer -# YEAR=2002 -# 1/4 Gerd Kortemeyer -# 6/24,7/2 H. K. Ng # Makes a table out of the previous attempts # Inputs result_from_symbread, user, domain, course_id @@ -47,96 +40,136 @@ Apache::loncommon - pile of common routi =head1 SYNOPSIS -Referenced by other mod_perl Apache modules. +Common routines for manipulating connections, student answers, + domains, common Javascript fragments, etc. -Invocation: - &Apache::loncommon::SUBROUTINENAME(ARGUMENTS); +=head1 OVERVIEW -=head1 INTRODUCTION - -Common collection of used subroutines. This collection helps remove +A collection of commonly used subroutines that don't have a natural +home anywhere else. This collection helps remove redundancy from other modules and increase efficiency of memory usage. -Current things done: - - Makes a table out of the previous homework attempts - Inputs result_from_symbread, user, domain, course_id - Reads in non-network-related .tab files - -This is part of the LearningOnline Network with CAPA project -described at http://www.lon-capa.org. - -=head2 General Subroutines - -=over 4 - =cut # End of POD header package Apache::loncommon; use strict; -use Apache::lonnet(); +use Apache::lonnet; use GDBM_File; use POSIX qw(strftime mktime); -use Apache::Constants qw(:common); -use Apache::lonmsg(); +use Apache::lonmenu(); +use Apache::lonenc(); +use Apache::lonlocal; +use HTML::Entities; +use Apache::lonhtmlcommon(); +use Apache::loncoursedata(); +use Apache::lontexconvert(); +use Apache::lonclonecourse(); +use LONCAPA qw(:DEFAULT :match); + +# ---------------------------------------------- Designs +use vars qw(%defaultdesign); + my $readit; -=pod -=item Global Variables +## +## Global Variables +## + + +# ----------------------------------------------- SSI with retries: +# + +=pod + +=head1 Server Side include with retries: =over 4 -=cut -# ----------------------------------------------- Filetypes/Languages/Copyright -my %language; -my %cprtag; -my %fe; my %fd; -my %category_extensions; +=item * &ssi_with_retries(resource,retries form) -# ---------------------------------------------- Designs +Performs an ssi with some number of retries. Retries continue either +until the result is ok or until the retry count supplied by the +caller is exhausted. -my %designhash; +Inputs: -# ---------------------------------------------- Thesaurus variables +=over 4 -=pod +resource - Identifies the resource to insert. -=item %Keywords +retries - Count of the number of retries allowed. -A hash used by &keyword to determine if a word is considered a keyword. +form - Hash that identifies the rendering options. -=item $thesaurus_db_file +=back -Scalar containing the full path to the thesaurus database. +Returns: -=cut +=over 4 -my %Keywords; -my $thesaurus_db_file; +content - The content of the response. If retries were exhausted this is empty. +response - The response from the last attempt (which may or may not have been successful. -=pod +=back =back =cut -# ----------------------------------------------------------------------- BEGIN +sub ssi_with_retries { + my ($resource, $retries, %form) = @_; -=pod -=item BEGIN() + my $ok = 0; # True if we got a good response. + my $content; + my $response; -Initialize values from language.tab, copyright.tab, filetypes.tab, -thesaurus.tab, and filecategories.tab. + # Try to get the ssi done. within the retries count: -=cut + do { + ($content, $response) = &Apache::lonnet::ssi($resource, %form); + $ok = $response->is_success; + if (!$ok) { + &Apache::lonnet::logthis("Failed ssi_with_retries on $resource: ".$response->is_success.', '.$response->code.', '.$response->message); + } + $retries--; + } while (!$ok && ($retries > 0)); + + if (!$ok) { + $content = ''; # On error return an empty content. + } + return ($content, $response); + +} + + + +# ----------------------------------------------- Filetypes/Languages/Copyright +my %language; +my %supported_language; +my %cprtag; +my %scprtag; +my %fe; my %fd; my %fm; +my %category_extensions; -# ----------------------------------------------------------------------- BEGIN +# ---------------------------------------------- Thesaurus variables +# +# %Keywords: +# A hash used by &keyword to determine if a word is considered a keyword. +# $thesaurus_db_file +# Scalar containing the full path to the thesaurus database. + +my %Keywords; +my $thesaurus_db_file; +# +# Initialize values from language.tab, copyright.tab, filetypes.tab, +# thesaurus.tab, and filecategories.tab. +# BEGIN { # Variable initialization $thesaurus_db_file = $Apache::lonnet::perlvar{'lonTabDir'}."/thesaurus.db"; @@ -144,82 +177,95 @@ BEGIN { unless ($readit) { # ------------------------------------------------------------------- languages { - my $fh=Apache::File->new($Apache::lonnet::perlvar{'lonTabDir'}. - '/language.tab'); - if ($fh) { - while (<$fh>) { - next if /^\#/; - chomp; - my ($key,$val)=(split(/\s+/,$_,2)); - $language{$key}=$val; - } - } + my $langtabfile = $Apache::lonnet::perlvar{'lonTabDir'}. + '/language.tab'; + if ( open(my $fh,"<$langtabfile") ) { + while (my $line = <$fh>) { + next if ($line=~/^\#/); + chomp($line); + my ($key,$two,$country,$three,$enc,$val,$sup)=(split(/\t/,$line)); + $language{$key}=$val.' - '.$enc; + if ($sup) { + $supported_language{$key}=$sup; + } + } + close($fh); + } } # ------------------------------------------------------------------ copyrights { - my $fh=Apache::File->new($Apache::lonnet::perlvar{'lonIncludes'}. - '/copyright.tab'); - if ($fh) { - while (<$fh>) { - next if /^\#/; - chomp; - my ($key,$val)=(split(/\s+/,$_,2)); - $cprtag{$key}=$val; - } - } + my $copyrightfile = $Apache::lonnet::perlvar{'lonIncludes'}. + '/copyright.tab'; + if ( open (my $fh,"<$copyrightfile") ) { + while (my $line = <$fh>) { + next if ($line=~/^\#/); + chomp($line); + my ($key,$val)=(split(/\s+/,$line,2)); + $cprtag{$key}=$val; + } + close($fh); + } } - -# -------------------------------------------------------------- domain designs - - my $filename; - my $designdir=$Apache::lonnet::perlvar{'lonTabDir'}.'/lonDomColors'; - opendir(DIR,$designdir); - while ($filename=readdir(DIR)) { - my ($domain)=($filename=~/^(\w+)\./); +# ----------------------------------------------------------- source copyrights { - my $fh=Apache::File->new($designdir.'/'.$filename); - if ($fh) { - while (<$fh>) { - next if /^\#/; - chomp; - my ($key,$val)=(split(/\=/,$_)); - if ($val) { $designhash{$domain.'.'.$key}=$val; } - } - } + my $sourcecopyrightfile = $Apache::lonnet::perlvar{'lonIncludes'}. + '/source_copyright.tab'; + if ( open (my $fh,"<$sourcecopyrightfile") ) { + while (my $line = <$fh>) { + next if ($line =~ /^\#/); + chomp($line); + my ($key,$val)=(split(/\s+/,$line,2)); + $scprtag{$key}=$val; + } + close($fh); + } } +# -------------------------------------------------------------- default domain designs + my $designdir=$Apache::lonnet::perlvar{'lonTabDir'}.'/lonDomColors'; + my $designfile = $designdir.'/default.tab'; + if ( open (my $fh,"<$designfile") ) { + while (my $line = <$fh>) { + next if ($line =~ /^\#/); + chomp($line); + my ($key,$val)=(split(/\=/,$line)); + if ($val) { $defaultdesign{$key}=$val; } + } + close($fh); } - closedir(DIR); - # ------------------------------------------------------------- file categories { - my $fh=Apache::File->new($Apache::lonnet::perlvar{'lonTabDir'}. - '/filecategories.tab'); - if ($fh) { - while (<$fh>) { - next if /^\#/; - chomp; - my ($extension,$category)=(split(/\s+/,$_,2)); - push @{$category_extensions{lc($category)}},$extension; - } - } + my $categoryfile = $Apache::lonnet::perlvar{'lonTabDir'}. + '/filecategories.tab'; + if ( open (my $fh,"<$categoryfile") ) { + while (my $line = <$fh>) { + next if ($line =~ /^\#/); + chomp($line); + my ($extension,$category)=(split(/\s+/,$line,2)); + push @{$category_extensions{lc($category)}},$extension; + } + close($fh); + } + } # ------------------------------------------------------------------ file types { - my $fh=Apache::File->new($Apache::lonnet::perlvar{'lonTabDir'}. - '/filetypes.tab'); - if ($fh) { - while (<$fh>) { - next if (/^\#/); - chomp; - my ($ending,$emb,$descr)=split(/\s+/,$_,3); - if ($descr ne '') { - $fe{$ending}=lc($emb); - $fd{$ending}=$descr; - } - } - } + my $typesfile = $Apache::lonnet::perlvar{'lonTabDir'}. + '/filetypes.tab'; + if ( open (my $fh,"<$typesfile") ) { + while (my $line = <$fh>) { + next if ($line =~ /^\#/); + chomp($line); + my ($ending,$emb,$mime,$descr)=split(/\s+/,$line,4); + if ($descr ne '') { + $fe{$ending}=lc($emb); + $fd{$ending}=$descr; + if ($mime ne 'unk') { $fm{$ending}=$mime; } + } + } + close($fh); + } } &Apache::lonnet::logthis( "INFO: Read file types"); @@ -227,21 +273,25 @@ BEGIN { } # end of unless($readit) } -# ============================================================= END BEGIN BLOCK + ############################################################### ## HTML and Javascript Helper Functions ## ############################################################### =pod -=item browser_and_searcher_javascript - -Returns scalar containing javascript to open a browser window -or a searcher window. Also creates +=head1 HTML and Javascript Functions =over 4 -=item openbrowser(formname,elementname,only,omit) [javascript] +=item * &browser_and_searcher_javascript() + +XXReturns a string +containing javascript with two functions, C and +C. Returned string does not contain EscriptE +tags. + +=item * &openbrowser(formname,elementname,only,omit) [javascript] inputs: formname, elementname, only, omit @@ -249,78 +299,118 @@ formname and elementname indicate the na the element that the results of the browsing selection are to be placed in. Specifying 'only' will restrict the browser to displaying only files -with the given extension. Can be a comma seperated list. +with the given extension. Can be a comma separated list. Specifying 'omit' will restrict the browser to NOT displaying files -with the given extension. Can be a comma seperated list. +with the given extension. Can be a comma separated list. -=item opensearcher(formname, elementname) [javascript] +=item * &opensearcher(formname,elementname) [javascript] Inputs: formname, elementname formname and elementname specify the name of the html form and the name of the element the selection from the search results will be placed in. -=back - =cut -############################################################### sub browser_and_searcher_javascript { + my ($mode)=@_; + if (!defined($mode)) { $mode='edit'; } + my $resurl=&escape_single(&lastresurl()); return < END } +sub lastresurl { + if ($env{'environment.lastresurl'}) { + return $env{'environment.lastresurl'} + } else { + return '/res'; + } +} + +sub storeresurl { + my $resurl=&Apache::lonnet::clutter(shift); + unless ($resurl=~/^\/res/) { return 0; } + $resurl=~s/\/$//; + &Apache::lonnet::put('environment',{'lastresurl' => $resurl}); + &Apache::lonnet::appenv({'environment.lastresurl' => $resurl}); + return 1; +} + sub studentbrowser_javascript { - unless ($ENV{'request.course.id'}) { return ''; } - unless (&Apache::lonnet::allowed('srm',$ENV{'request.course.id'})) { - return ''; - } + unless ( + (($env{'request.course.id'}) && + (&Apache::lonnet::allowed('srm',$env{'request.course.id'}) + || &Apache::lonnet::allowed('srm',$env{'request.course.id'}. + '/'.$env{'request.course.sec'}) + )) + || ($env{'request.role'}=~/^(au|dc|su)/) + ) { return ''; } return (<<'ENDSTDBRW'); +ENDAUTHORBRW +} + +sub coursebrowser_javascript { + my ($domainfilter,$sec_element,$formname)=@_; + my $crs_or_grp_alert = &mt('Please select the type of LON-CAPA entity - Course or Group - for which you wish to add/modify a user role'); + my $output = ' +'; + return $output; +} + +sub setsec_javascript { + my ($sec_element,$formname) = @_; + my $setsections = qq| +function setSect(sectionlist) { + var sectionsArray = new Array(); + if ((sectionlist != '') && (typeof sectionlist != "undefined")) { + sectionsArray = sectionlist.split(","); + } + var numSections = sectionsArray.length; + document.$formname.$sec_element.length = 0; + if (numSections == 0) { + document.$formname.$sec_element.multiple=false; + document.$formname.$sec_element.size=1; + document.$formname.$sec_element.options[0] = new Option('No existing sections','',false,false) + } else { + if (numSections == 1) { + document.$formname.$sec_element.multiple=false; + document.$formname.$sec_element.size=1; + document.$formname.$sec_element.options[0] = new Option('Select','',true,true); + document.$formname.$sec_element.options[1] = new Option('No section','',false,false) + document.$formname.$sec_element.options[2] = new Option(sectionsArray[0],sectionsArray[0],false,false); + } else { + for (var i=0; i".&mt('Select Course').""; +} + +sub selectauthor_link { + my ($form,$udom)=@_; + return ''. + &mt('Select Author').''; +} + +sub check_uncheck_jscript { + my $jscript = <<"ENDSCRT"; +function checkAll(field) { + if (field.length > 0) { + for (i = 0; i < field.length; i++) { + field[i].checked = true ; + } + } else { + field.checked = true + } +} + +function uncheckAll(field) { + if (field.length > 0) { + for (i = 0; i < field.length; i++) { + field[i].checked = false ; + } + } else { + field.checked = false ; + } +} +ENDSCRT + return $jscript; } -############################################################### =pod -=item linked_select_forms(...) +=item * &linked_select_forms(...) linked_select_forms returns a string containing a block and html for two tags -=item $middletext, the text which appears between the tag -=item $firstselectname, the name of the first tag -=item $secondselectname, the name of the second element int multiple mode + + +Args: + $name - name of the "; + my @order; + if (ref($order) eq 'ARRAY') { + @order = @{$order}; + } else { + @order = sort(keys(%$hash)); + } + if (exists($$hash{'select_form_order'})) { + @order = @{$$hash{'select_form_order'}}; + } + + foreach my $key (@order) { + $output.='\n"; + } + $output.="\n"; + return $output; +} + #------------------------------------------- =pod -=item get_domains() +=item * &select_form($defdom,$name,%hash) -Returns an array containing each of the domains listed in the hosts.tab -file. +Returns a string containing a \n"; + my @keys; + if (exists($hash{'select_form_order'})) { + @keys=@{$hash{'select_form_order'}}; + } else { + @keys=sort(keys(%hash)); + } + foreach my $key (@keys) { + $selectform.= + '\n"; + } + $selectform.=""; + return $selectform; +} + +# For display filters + +sub display_filter { + if (!$env{'form.show'}) { $env{'form.show'}=10; } + if (!$env{'form.displayfilter'}) { $env{'form.displayfilter'}='currentfolder'; } + return ' '. + &mt('Filter [_1]', + &select_form($env{'form.displayfilter'}, + 'displayfilter', + ('currentfolder' => 'Current folder/page', + 'containing' => 'Containing phrase', + 'none' => 'None'))). + ''; +} + +sub gradeleveldescription { + my $gradelevel=shift; + my %gradelevels=(0 => 'Not specified', + 1 => 'Grade 1', + 2 => 'Grade 2', + 3 => 'Grade 3', + 4 => 'Grade 4', + 5 => 'Grade 5', + 6 => 'Grade 6', + 7 => 'Grade 7', + 8 => 'Grade 8', + 9 => 'Grade 9', + 10 => 'Grade 10', + 11 => 'Grade 11', + 12 => 'Grade 12', + 13 => 'Grade 13', + 14 => '100 Level', + 15 => '200 Level', + 16 => '300 Level', + 17 => '400 Level', + 18 => 'Graduate Level'); + return &mt($gradelevels{$gradelevel}); +} + +sub select_level_form { + my ($deflevel,$name)=@_; + unless ($deflevel) { $deflevel=0; } + my $selectform = ""; + return $selectform; } #------------------------------------------- =pod -=item select_dom_form($defdom,$name) +=item * &select_dom_form($defdom,$name,$includeempty,$showdomdesc) Returns a string containing a \n"; - foreach (@domains) { - $selectdomain.="\n"; + foreach my $dom (@domains) { + $selectdomain.="\n"; } $selectdomain.=""; return $selectdomain; @@ -626,51 +1700,149 @@ sub select_dom_form { =pod -=item get_library_servers($domain) +=item * &home_server_form_item($domain,$name,$defaultflag) + +input: 4 arguments (two required, two optional) - + $domain - domain of new user + $name - name of form element + $default - Value of 'default' causes a default item to be first + option, and selected by default. + $hide - Value of 'hide' causes hiding of the name of the server, + if 1 server found, or default, if 0 found. +output: returns 2 items: +(a) form element which contains either: + (i) + form item if there are multiple library servers in $domain, or + (ii) an form item + if there is only one library server in $domain. -Returns a hash which contains keys like '103l3' and values like -'kirk.lite.msu.edu'. All of the keys will be for machines in the -given $domain. +(b) number of library servers found. + +See loncreateuser.pm for example of use. =cut #------------------------------------------- -sub get_library_servers { - my $domain = shift; - my %library_servers; - foreach (keys(%Apache::lonnet::libserv)) { - if ($Apache::lonnet::hostdom{$_} eq $domain) { - $library_servers{$_} = $Apache::lonnet::hostname{$_}; +sub home_server_form_item { + my ($domain,$name,$default,$hide) = @_; + my %servers = &Apache::lonnet::get_servers($domain,'library'); + my $result; + my $numlib = keys(%servers); + if ($numlib > 1) { + $result .= ''."\n"; + } elsif ($numlib == 1) { + my $hostid; + foreach my $item (keys(%servers)) { + $hostid = $item; } + $result .= ''; + if (!$hide) { + $result .= $hostid.' '.$servers{$hostid}; + } + $result .= "\n"; + } elsif ($default) { + $result .= ''; + if (!$hide) { + $result .= &mt('default'); + } + $result .= "\n"; } - return %library_servers; + return ($result,$numlib); } -#------------------------------------------- +=pod + +=back + +=cut + +############################################################### +## Decoding User Agent ## +############################################################### =pod -=item home_server_option_list($domain) +=head1 Decoding the User Agent + +=over 4 -returns a string which contains an