--- loncom/interface/lonsearchcat.pm 2002/06/20 14:31:31 1.124 +++ loncom/interface/lonsearchcat.pm 2007/03/12 17:06:15 1.281 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Search Catalog # -# $Id: lonsearchcat.pm,v 1.124 2002/06/20 14:31:31 matthew Exp $ +# $Id: lonsearchcat.pm,v 1.281 2007/03/12 17:06:15 albertel Exp $ # # Copyright Michigan State University Board of Trustees # @@ -25,14 +25,6 @@ # # http://www.lon-capa.org/ # -# YEAR=2001 -# 3/8, 3/12, 3/13, 3/14, 3/15, 3/19 Scott Harrison -# 3/20, 3/21, 3/22, 3/26, 3/27, 4/2, 8/15, 8/24, 8/25 Scott Harrison -# 10/12,10/14,10/15,10/16,11/28,11/29,12/10,12/12,12/16 Scott Harrison -# YEAR=2002 -# 1/17 Scott Harrison -# 6/17 Matthew Hall -# ############################################################################### ############################################################################### @@ -40,7 +32,7 @@ =head1 NAME -lonsearchcat +lonsearchcat - LONCAPA Search Interface =head1 SYNOPSIS @@ -56,7 +48,7 @@ described at http://www.lon-capa.org. lonsearchcat presents the user with an interface to search the LON-CAPA digital library. lonsearchcat also initiates the execution of a search by sending the search parameters to LON-CAPA servers. The progress of -search (on a server basis) is displayed to the user in a seperate window. +search (on a server basis) is displayed to the user in a separate window. =head1 Internals @@ -67,115 +59,1032 @@ search (on a server basis) is displayed ############################################################################### ############################################################################### -## ## -## ORGANIZATION OF THIS PERL MODULE ## -## ## -## 1. Modules used by this module ## -## 2. Choices for different output views (detailed, summary, xml, etc) ## -## 3. BEGIN block (to be run once after compilation) ## -## 4. Handling routine called via Apache and mod_perl ## -## 5. Other subroutines ## -## ## -############################################################################### - package Apache::lonsearchcat; -# ------------------------------------------------- modules used by this module use strict; -use Apache::Constants qw(:common); -use Apache::lonnet(); +use Apache::Constants qw(:common :http); +use Apache::lonnet; use Apache::File(); use CGI qw(:standard); use Text::Query; use GDBM_File; use Apache::loncommon(); - -# ---------------------------------------- variables used throughout the module +use Apache::lonmysql(); +use Apache::lonmeta; +use Apache::lonhtmlcommon; +use Apache::lonlocal; +use LONCAPA::lonmetadata(); +use HTML::Entities(); +use Parse::RecDescent; +use Apache::lonnavmaps; +use Apache::lonindexer(); +use LONCAPA; ###################################################################### ###################################################################### +## +## Global variables +## +###################################################################### +###################################################################### +my %groupsearch_db; # Database hash used to save values for the + # groupsearch RAT interface. +my %persistent_db; # gdbm hash which holds data which is supposed to + # persist across calls to lonsearchcat.pm + +# The different view modes and associated functions + +my %Views = ("detailed" => \&detailed_citation_view, + "detailedpreview" => \&detailed_citation_preview, + "summary" => \&summary_view, + "summarypreview" => \&summary_preview, + "fielded" => \&fielded_format_view, + "xml" => \&xml_sgml_view, + "compact" => \&compact_view); -=pod +###################################################################### +###################################################################### +sub handler { + my $r = shift; +# &set_defaults(); + # + # set form defaults + # + my $hidden_fields;# Hold all the hidden fields used to keep track + # of the search system state + my $importbutton; # button to take the selected results and go to group + # sorting + my $diropendb; # The full path to the (temporary) search database file. + # This is set and used in &handler() and is also used in + # &output_results(). -=item Global variables + my $loaderror=&Apache::lonnet::overloaderror($r); + if ($loaderror) { return $loaderror; } + # + my $closebutton; # button that closes the search window + # This button is different for the RAT compared to + # normal invocation. + # + &Apache::loncommon::content_type($r,'text/html'); + $r->send_http_header; + return OK if $r->header_only; + ## + ## Prevent caching of the search interface window. Hopefully this means + ## we will get the launch=1 passed in a little more. + &Apache::loncommon::no_cache($r); + ## + ## Pick up form fields passed in the links. + ## + &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, + ['catalogmode','launch','acts','mode','form','element','pause', + 'phase','persistent_db_id','table','start','show', + 'cleargroupsort','titleelement','area']); + ## + ## The following is a trick - we wait a few seconds if asked to so + ## the daemon running the search can get ahead of the daemon + ## printing the results. We only need (theoretically) to do + ## this once, so the pause indicator is deleted + ## + if (exists($env{'form.pause'})) { + sleep(1); + delete($env{'form.pause'}); + } + ## + ## Initialize global variables + ## + my $domain = $r->dir_config('lonDefDomain'); + $diropendb= "/home/httpd/perl/tmp/". + "$env{'user.domain'}_$env{'user.name'}_sel_res.db"; + # + # set the name of the persistent database + # $env{'form.persistent_db_id'} can only have digits in it. + if (! exists($env{'form.persistent_db_id'}) || + ($env{'form.persistent_db_id'} =~ /\D/) || + ($env{'form.launch'} eq '1')) { + $env{'form.persistent_db_id'} = time; + } -=over 4 + my $persistent_db_file = "/home/httpd/perl/tmp/". + &escape($domain). + '_'.&escape($env{'user.name'}). + '_'.$env{'form.persistent_db_id'}.'_persistent_search.db'; + ## + &Apache::lonhtmlcommon::clear_breadcrumbs(); -=item %hostdomains + my @allowed_searches = ('portfolio'); + if (&Apache::lonnet::allowed('bre',$env{'request.role.domain'})) { + push(@allowed_searches,'res'); + } + if (exists($env{'request.course.id'}) && $env{'request.course.id'} ne '') { + push(@allowed_searches,'course'); + } + my $crumb_text = 'Portfolio Search'; + if (@allowed_searches == 3) { + $crumb_text = 'Course, Portfolio and Catalog Search'; + } elsif (@allowed_searches ==2) { + if (grep(/^res$/,@allowed_searches)) { + $crumb_text = 'Portfolio and Catalog Search'; + } elsif (grep(/^course$/,@allowed_searches)) { + $crumb_text = 'Portfolio and Course Search'; + } + } + &Apache::lonhtmlcommon::add_breadcrumb + ({href=>'/adm/searchcat?'. + 'catalogmode='.$env{'form.catalogmode'}. + '&launch='.$env{'form.launch'}. + '&mode='.$env{'form.mode'}, + text=>"$crumb_text", + target=>'_top', + bug=>'Searching',}); + # + if ($env{'form.phase'} !~ m/(basic|adv|course)_search/) { + if (! &get_persistent_form_data($persistent_db_file)) { + if ($env{'form.phase'} =~ /(run_search|results)/) { + &Apache::lonnet::logthis('lonsearchcat:'. + 'Unable to recover data from '. + $persistent_db_file); + my $msg = + 'We were unable to retrieve data describing your search. '. + 'This is a serious error and has been logged. '. + 'Please alert your LON-CAPA administrator.'; + &Apache::loncommon::simple_error_page($r,'Search Error', + $msg); + return OK; + } + } + } else { + &clean_up_environment(); + } + ## + ## Clear out old values from groupsearch database + ## + untie %groupsearch_db if (tied(%groupsearch_db)); + if (($env{'form.cleargroupsort'} eq '1') || + (($env{'form.launch'} eq '1') && + ($env{'form.catalogmode'} eq 'import'))) { + if (tie(%groupsearch_db,'GDBM_File',$diropendb,&GDBM_WRCREAT(),0640)) { + &start_fresh_session(); + untie %groupsearch_db; + delete($env{'form.cleargroupsort'}); + } else { + # This is a stupid error to give to the user. + # It really tells them nothing. + my $msg = 'Unable to tie hash to db file.'; + &Apache::loncommon::simple_error_page($r,'Search Error', + $msg); + return OK; + } + } + ## + ## Configure hidden fields + ## + $hidden_fields = ''."\n"; + if (exists($env{'form.catalogmode'})) { + $hidden_fields .= &hidden_field('catalogmode'); + } + if (exists($env{'form.form'})) { + $hidden_fields .= &hidden_field('form'); + } + if (exists($env{'form.element'})) { + $hidden_fields .= &hidden_field('element'); + } + if (exists($env{'form.titleelement'})) { + $hidden_fields .= &hidden_field('titleelement'); + } + if (exists($env{'form.mode'})) { + $hidden_fields .= &hidden_field('mode'); + } + if (exists($env{'form.area'})) { + $hidden_fields .= &hidden_field('area'); + } + ## + ## Configure dynamic components of interface + ## + if ($env{'form.catalogmode'} eq 'interactive') { + $closebutton=" +END + } else { + $closebutton = ''; + $importbutton = ''; + } + ## + ## Sanity checks on form elements + ## + if (!defined($env{'form.viewselect'})) { + $env{'form.viewselect'} ="summary"; + } + $env{'form.phase'} = 'disp_basic' if (! exists($env{'form.phase'})); + $env{'form.show'} = 20 if (! exists($env{'form.show'})); + # + $env{'form.searchmode'} = 'basic' if (! exists($env{'form.searchmode'})); + if ($env{'form.phase'} eq 'adv_search' || + $env{'form.phase'} eq 'disp_adv') { + $env{'form.searchmode'} = 'advanced'; + } elsif ($env{'form.phase'} eq 'course_search') { + $env{'form.searchmode'} = 'course_search'; + } + # + if ($env{'form.searchmode'} eq 'advanced') { + my $srchtype = 'Catalog'; + if ($env{'form.area'} eq 'portfolio') { + $srchtype = 'Portfolio'; + } + &Apache::lonhtmlcommon::add_breadcrumb + ({href=>'/adm/searchcat?phase=disp_adv&'. + 'catalogmode='.$env{'form.catalogmode'}. + '&launch='.$env{'form.launch'}. + '&mode='.$env{'form.mode'}, + text=>"Advanced $srchtype Search", + bug=>'Searching',}); + } elsif ($env{'form.searchmode'} eq 'course search') { + &Apache::lonhtmlcommon::add_breadcrumb + ({href=>'/adm/searchcat?phase=disp_adv&'. + 'catalogmode='.$env{'form.catalogmode'}. + '&launch='.$env{'form.launch'}. + '&mode='.$env{'form.mode'}, + text=>"Course Search", + bug=>'Searching',}); + } + ## + ## Switch on the phase + ## + if ($env{'form.phase'} eq 'disp_basic') { + &print_basic_search_form($r,$closebutton,$hidden_fields); + } elsif ($env{'form.phase'} eq 'disp_adv') { + &print_advanced_search_form($r,$closebutton,$hidden_fields); + } elsif ($env{'form.phase'} eq 'results') { + &display_results($r,$importbutton,$closebutton,$diropendb, + $env{'form.area'}); + } elsif ($env{'form.phase'} =~ /^(sort|run_search)$/) { + my ($query,$customquery,$customshow,$libraries,$pretty_string) = + &get_persistent_data($persistent_db_file, + ['query','customquery','customshow', + 'libraries','pretty_string']); + if ($env{'form.phase'} eq 'sort') { + &print_sort_form($r,$pretty_string); + } elsif ($env{'form.phase'} eq 'run_search') { + &run_search($r,$query,$customquery,$customshow, + $libraries,$pretty_string,$env{'form.area'}); + } + } elsif ($env{'form.phase'} eq 'course_search') { + &course_search($r); + } elsif(($env{'form.phase'} eq 'basic_search') || + ($env{'form.phase'} eq 'adv_search')) { + # + # We are running a search, try to parse it + my ($query,$customquery,$customshow,$libraries) = + (undef,undef,undef,undef); + my $pretty_string; + if ($env{'form.phase'} eq 'basic_search') { + ($query,$pretty_string,$libraries) = + &parse_basic_search($r,$closebutton,$hidden_fields); + return OK if (! defined($query)); + &make_persistent({ basicexp => $env{'form.basicexp'}}, + $persistent_db_file); + } else { # Advanced search + ($query,$customquery,$customshow,$libraries,$pretty_string) + = &parse_advanced_search($r,$closebutton,$hidden_fields); + return OK if (! defined($query)); + } + &make_persistent({ query => $query, + customquery => $customquery, + customshow => $customshow, + libraries => $libraries, + pretty_string => $pretty_string }, + $persistent_db_file); + # + # Set up table + if (! defined(&create_results_table($env{'form.area'}))) { + my $errorstring=&Apache::lonmysql::get_error(); + &Apache::lonnet::logthis('lonsearchcat.pm: Unable to create '. + 'needed table. lonmysql error:'. + $errorstring); + + my $msg = + 'Unable to create table in which to store search results. '. + 'The search has been aborted.'; + &Apache::loncommon::simple_error_page($r,'Search Error', + $msg); + return OK; + } + delete($env{'form.launch'}); + if (! &make_form_data_persistent($r,$persistent_db_file)) { + my $msg= + 'Unable to properly store search information. '. + 'The search has been aborted.'; + &Apache::loncommon::simple_error_page($r,'Search Error', + $msg); + return OK; + } + ## + ## Print out the frames interface + ## + if (defined($query)) { + &print_frames_interface($r); + } + } + return OK; +} -matches host name to host domain +# +# The mechanism used to store values away and retrieve them does not +# handle the case of missing environment variables being significant. +# +# This routine sets non existant checkbox form elements to ''. +# +sub clean_up_environment { + if ($env{'form.phase'} eq 'basic_search') { + if (! exists($env{'form.related'})) { + $env{'form.related'} = ''; + } + if (! exists($env{'form.domains'})) { + $env{'form.domains'} = ''; + } + } elsif ($env{'form.phase'} eq 'adv_search') { + foreach my $field ('title','keywords','notes', + 'abstract','standards','mime') { + if (! exists($env{'form.'.$field.'_related'})) { + $env{'form.'.$field.'_related'} = ''; + } + } + } elsif ($env{'form.phase'} eq 'course_search') { + if (! exists($env{'form.crsrelated'})) { + $env{'form.crsrelated'} = ''; + } + } +} -=item %hostips +sub hidden_field { + my ($name,$value) = @_; + if (! defined($value)) { + $value = $env{'form.'.$name}; + } + return ''.$/; +} -matches host name to host ip +###################################################################### +###################################################################### +## +## Course Search +## +###################################################################### +###################################################################### +{ # Scope the course search to avoid global variables +# +# Variables For course search +my %alreadyseen; +my %hash; +my $totalfound; + +sub make_symb { + my ($id)=@_; + my ($mapid,$resid)=split(/\./,$id); + my $map=$hash{'map_id_'.$mapid}; + my $res=$hash{'src_'.$id}; + my $symb=&Apache::lonnet::encode_symb($map,$resid,$res); + return $symb; +} + +sub course_search { + my $r=shift; + my $pretty_search_string = ''.$env{'form.courseexp'}.''; + my $search_string = $env{'form.courseexp'}; + my @New_Words; + undef(%alreadyseen); + if ($env{'form.crsrelated'}) { + ($search_string,@New_Words) = &related_version($env{'form.courseexp'}); + if (@New_Words) { + $pretty_search_string .= ' '.&mt("with related words").": @New_Words."; + } else { + $pretty_search_string .= ' '.&mt('with no related words')."."; + } + } + my $fulltext=$env{'form.crsfulltext'}; + my $discuss=$env{'form.crsdiscuss'}; + my @allwords=($search_string,@New_Words); + $totalfound=0; + $r->print(&Apache::loncommon::start_page('Course Search'). + '
'.&mt('No matches found in resources').'.
'); + } -=item %hitcount +# Check discussions if requested + if ($discuss) { + my $totaldiscussions = 0; + $r->print(''.&mt('No matches found in postings').'.
'); + } + } + +# =================================================== Done going through course + $r->print(&Apache::loncommon::end_page()); +} -stores number of hits per host +# =============================== This pulls up a resource and its dependencies -=item $closebutton +sub checkonthis { + my ($r,$id,$url,$level,$title,$fulltext,$symb,@allwords)=@_; + $alreadyseen{$id}=1; + if (&Apache::loncommon::connection_aborted($r)) { return; } + $r->rflush(); + + my $result=$title.' '; + if ($env{'request.role.adv'} || !$hash{'encrypted_'.$id}) { + $result.=&Apache::lonnet::metadata($url,'title').' '. + &Apache::lonnet::metadata($url,'subject').' '. + &Apache::lonnet::metadata($url,'abstract').' '. + &Apache::lonnet::metadata($url,'keywords'); + } + my ($extension)=($url=~/\.(\w+)$/); + if (&Apache::loncommon::fileembstyle($extension) eq 'ssi' && + ($url) && ($fulltext)) { + $result.=&Apache::lonnet::ssi_body($url.'?symb='.&escape($symb)); + } + $result=~s/\s+/ /gs; + my $applies = 0; + $applies = &checkwords($result,$applies,@allwords); +# Does this resource apply? + if ($applies) { + $r->print('+$lt{'note'}. +
++
+ENDCOURSESEARCH
+ $scrout.=' '.
+ &Apache::lonhtmlcommon::textbox('courseexp',
+ $env{'form.courseexp'},40);
+ my $crscheckbox =
+ &Apache::lonhtmlcommon::checkbox('crsfulltext',
+ $env{'form.crsfulltext'});
+ my $relcheckbox =
+ &Apache::lonhtmlcommon::checkbox('crsrelated',
+ $env{'form.crsrelated'});
+ my $discheckbox =
+ &Apache::lonhtmlcommon::checkbox('crsdiscuss',
+ $env{'form.crsrelated'});
+ $scrout.=(< | |
+ +
++Search: $pretty_query_string +
+ +END + $r->print($result.&Apache::loncommon::end_page()); + return; +} + +##################################################################### +##################################################################### + +=pod + +=item MySQL Table Description + +MySQL table creation requires a precise description of the data to be +stored. The use of the correct types to hold data is vital to efficient +storage and quick retrieval of records. The columns must be described in +the following format: + +=cut + +##################################################################### +##################################################################### +# +# These should probably be scoped but I don't have time right now... +# +my @Datatypes; +my @Fullindicies; + +###################################################################### +###################################################################### + +=pod + +=item &create_results_table() + +Creates the table of search results by calling lonmysql. Stores the +table id in $env{'form.table'} + +Inputs: search area - either res or portfolio + +Returns: the identifier of the table on success, undef on error. + +=cut + +###################################################################### +###################################################################### +sub set_up_table_structure { + my ($tabletype) = @_; + my ($datatypes,$fullindicies) = + &LONCAPA::lonmetadata::describe_metadata_storage($tabletype); + # Copy the table description before modifying it... + @Datatypes = @{$datatypes}; + unshift(@Datatypes,{name => 'id', + type => 'MEDIUMINT', + restrictions => 'UNSIGNED NOT NULL', + primary_key => 'yes', + auto_inc => 'yes' }); + @Fullindicies = @{$fullindicies}; + return; +} + +sub create_results_table { + my ($area) = @_; + if ($area eq 'portfolio') { + &set_up_table_structure('portfolio_search'); + } else { + &set_up_table_structure('metadata'); + } + my $table = &Apache::lonmysql::create_table + ( { columns => \@Datatypes, + FULLTEXT => [{'columns' => \@Fullindicies},], + } ); + if (defined($table)) { + $env{'form.table'} = $table; + return $table; + } + return undef; # Error... +} + +###################################################################### +###################################################################### + +=pod + +=item Search Status update functions + +Each of the following functions changes the values of one of the +input fields used to display the search status to the user. The names +should be explanatory. + +Inputs: Apache request handler ($r), text to display. + +Returns: Nothing. + +=over 4 + +=item &update_count_status() + +=item &update_status() + +=item &update_seconds() + +=back + +=cut + +###################################################################### +###################################################################### +sub update_count_status { + my ($r,$text) = @_; + $text =~ s/\'/\\\'/g; + $r->print + ("\n"); + $r->rflush(); +} + +sub update_status { + my ($r,$text) = @_; + $text =~ s/\'/\\\'/g; + $r->print + ("\n"); + $r->rflush(); +} + +{ + my $max_time = 300; # seconds for the search to complete + my $start_time = 0; + my $last_time = 0; + +sub reset_timing { + $start_time = 0; + $last_time = 0; +} + +sub time_left { + if ($start_time == 0) { + $start_time = time; + } + my $time_left = $max_time - (time - $start_time); + $time_left = 0 if ($time_left < 0); + return $time_left; +} + +sub update_seconds { + my ($r) = @_; + my $time = &time_left(); + if (($last_time-$time) > 0) { + $r->print("\n"); + $r->rflush(); + } + $last_time = $time; +} + +} + +###################################################################### +###################################################################### + +=pod + +=item &revise_button() + +Inputs: None + +Returns: html string for a 'revise search' button. + +=cut + +###################################################################### +###################################################################### +sub revise_button { + my $revise_phase = 'disp_basic'; + $revise_phase = 'disp_adv' if ($env{'form.searchmode'} eq 'advanced'); + my $newloc = '/adm/searchcat'. + '?persistent_db_id='.$env{'form.persistent_db_id'}. + '&cleargroupsort=1'. + '&phase='.$revise_phase; + my $result = qq{ }; + return $result; +} + +###################################################################### +###################################################################### + +=pod + +=item &run_search() + +Executes a search query by sending it the the other servers and putting the +results into MySQL. + +=cut + +###################################################################### +###################################################################### +sub run_search { + my ($r,$query,$customquery,$customshow,$serverlist, + $pretty_string,$area) = @_; + my $tabletype = 'metadata'; + if ($area eq 'portfolio') { + $tabletype = 'portfolio_search'; + } + my $connection = $r->connection; + # + # Print run_search header + # + my $start_page = &Apache::loncommon::start_page('Search Status',undef, + {'no_title' => 1}); + my $breadcrumbs = + &Apache::lonhtmlcommon::breadcrumbs('Searching','Searching', + $env{'form.catalogmode'} ne 'import'); + $r->print(<'.
+ ' | '. + &prev_next_buttons($min,$env{'form.show'},$total_results). + ' | '. + &viewoptions().' |
\n"; + if (! defined($Fields{'title'}) || $Fields{'title'} eq '') { + $Fields{'title'} = 'Untitled'; + } + my $prefix=&catalogmode_output($Fields{'title'},$Fields{'url'}, + $Fields{'id'},$checkbox_num++); + # Render the result into html + $output.= &$viewfunction($prefix,%Fields); + # Print them out as they come in. + $r->print($output); + $r->rflush(); + } + if (@Results < 1) { + $r->print(&mt("There were no results matching your query")); + } else { + $r->print + ('
-Subject: $subject
-Keyword(s): $keywords
-Notes: $notes
-MIME Type:
-END
- $result.=&Apache::loncommon::filedescription($mime);
- $result.=<
-$shortabstract -
-END + my ($prefix,%values) = @_; + my $result; + my $jumpurl=$values{'url'}; + $jumpurl=~s|^/ext/|http://|; + $result .= ''.$prefix. + ''.' '. + ''.$values{'title'}."\n"; + $result .= "\n";
+ $result .= ''.$values{'author'}.','.
+ ' '.$values{'owner'}.'
';
+ foreach my $field
+ (
+ { name=>'url',
+ translate => 'URL: [_1]',
+ special => 'url link',},
+ { name=>'subject',
+ translate => 'Subject: [_1]',},
+ { name=>'keywords',
+ translate => 'Keywords: [_1]',},
+ { name=>'notes',
+ translate => 'Notes: [_1]',},
+ { name=>'mimetag',
+ translate => 'MIME Type: [_1]',},
+ { name=>'standards',
+ translate => 'Standards:[_1]',},
+ { name=>'copyrighttag',
+ translate => 'Copyright/Distribution: [_1]',},
+ { name=>'count',
+ format => "%d",
+ translate => 'Access Count: [_1]',},
+ { name=>'stdno',
+ format => "%d",
+ translate => 'Number of Students: [_1]',},
+ { name=>'avetries',
+ format => "%.2f",
+ translate => 'Average Tries: [_1]',},
+ { name=>'disc',
+ format => "%.2f",
+ translate => 'Degree of Discrimination: [_1]',},
+ { name=>'difficulty',
+ format => "%.2f",
+ translate => 'Degree of Difficulty: [_1]',},
+ { name=>'clear',
+ format => "%.2f",
+ translate => 'Clear: [_1]',},
+ { name=>'depth',
+ format => "%.2f",
+ translate => 'Depth: [_1]',},
+ { name=>'helpful',
+ format => "%.2f",
+ translate => 'Helpful: [_1]',},
+ { name=>'correct',
+ format => "%.2f",
+ translate => 'Correct: [_1]',},
+ { name=>'technical',
+ format => "%.2f",
+ translate => 'Technical: [_1]',},
+ { name=>'comefrom_list',
+ type => 'list',
+ translate => 'Resources that lead up to this resource in maps',},
+ { name=>'goto_list',
+ type => 'list',
+ translate => 'Resources that follow this resource in maps',},
+ { name=>'sequsage_list',
+ type => 'list',
+ translate => 'Resources using or importing resource',},
+ ) {
+ next if (! exists($values{$field->{'name'}}) ||
+ $values{$field->{'name'}} eq '');
+ if (exists($field->{'type'}) && $field->{'type'} eq 'list') {
+ $result .= ''.&mt($field->{'translate'}).'';
+ foreach my $item (split(',',$values{$field->{'name'}})){
+ $result .=
+ &Apache::lonhtmlcommon::crumbs(&Apache::lonnet::clutter($item),
+ 'preview',
+ '',
+ (($env{'form.catalogmode'} eq 'import')?'parent.statusframe.document.forms.statusform':''),2,0,1);
+ }
+ } elsif (exists($field->{'format'}) && $field->{'format'} ne ''){
+ $result.= &mt($field->{'translate'},
+ sprintf($field->{'format'},
+ $values{$field->{'name'}}))."
\n";
+ } else {
+ if ($field->{'special'} eq 'url link') {
+ if ($jumpurl=~/^http\:\/\//) {
+ $result.=''.$jumpurl.'';
+ } else {
+ $result .=
+ &Apache::lonhtmlcommon::crumbs($jumpurl,
+ 'preview',
+ '',
+ (($env{'form.catalogmode'} eq 'import')?'parent.statusframe.document.forms.statusform':''),3,0,1);
+ }
+ } else {
+ $result.= &mt($field->{'translate'},
+ $values{$field->{'name'}});
+ }
+ $result .= "
\n";
+ }
+ }
+ $result .= "
'.$values{'extrashow'}.'
'; + } + if (exists($values{'shortabstract'}) && $values{'shortabstract'} ne '') { + $result .= ''.$values{'shortabstract'}.'
'; + } + $result .= ''. + &detailed_citation_view($prefix,%values). + ' | '. + &Apache::lonindexer::showpreview($values{'url'}). + ' |
'. + &summary_view($prefix,%values). + ' | '. + &Apache::lonindexer::showpreview($values{'url'}). + ' |
+$errorstring +
++$revise +
+$end_page +ENDPAGE } ###################################################################### @@ -1691,41 +3778,42 @@ sub filled { =item &output_blank_field_error() +Output a complete page that indicates the user has not filled in enough +information to do a search. + +Inputs: $r (Apache request handle), $closebutton, $parms. + +Returns: nothing + +$parms is extra information to include in the 'Revise search request' link. + =cut ###################################################################### ###################################################################### sub output_blank_field_error { - my ($r)=@_; - # make query information persistent to allow for subsequent revision - my $persistent=&make_persistent(); - - $r->print(<-Incorrect search query due to blank entry fields. -You need to fill in the relevant -fields on the search page in order for a query to be -processed. +$errormsg
- - -RESULTS ++$revise +
+$end_page +ENDPAGE + return; } ###################################################################### @@ -1737,35 +3825,34 @@ RESULTS Output a full html page with an error message. +Inputs: + + $r, the request pointer. + $message, the error message for the user. + $closebutton, the specialized close button needed for groupsearch. + =cut ###################################################################### ###################################################################### sub output_date_error { - my ($r,$message)=@_; + my ($r,$message,$closebutton,$hidden_fields)=@_; # make query information persistent to allow for subsequent revision - my $persistent=&make_persistent(); - + my $start_page = &Apache::loncommon::start_page('Search'); + my $end_page = &Apache::loncommon::end_page(); $r->print(<$message
- - +$end_page RESULTS } @@ -1776,7 +3863,7 @@ RESULTS =item &start_fresh_session() -Cleans the global %hash by removing all fields which begin with +Cleans the global %groupsearch_db by removing all fields which begin with 'pre_' or 'store'. =cut @@ -1784,260 +3871,34 @@ Cleans the global %hash by removing all ###################################################################### ###################################################################### sub start_fresh_session { - delete $hash{'mode_catalog'}; - foreach (keys %hash) { + delete $groupsearch_db{'mode_catalog'}; + foreach (keys %groupsearch_db) { if ($_ =~ /^pre_/) { - delete $hash{$_}; + delete $groupsearch_db{$_}; } if ($_ =~ /^store/) { - delete $hash{$_}; + delete $groupsearch_db{$_}; } } } -###################################################################### -###################################################################### - -=pod - -=item &popwin_js() send javascript to popwin - -=cut +1; -###################################################################### -###################################################################### -sub popwin_js { - # Print javascript out to popwin, but make sure we dont generate - # any javascript errors in doing so. - my ($r,$text) = @_; - $r->print(<<"END"); - -END - $r->rflush(); + &untiehash(); + &Apache::lonmysql::disconnect_from_db(); + return OK; } -###################################################################### -###################################################################### - -=pod - -=item &popwin_imgupdate() - -=cut - -###################################################################### -###################################################################### -sub popwin_imgupdate { - my ($r,$imgnum,$icon) = @_; - &popwin_js($r,'popwin.document.img'.$imgnum.'.'. - 'src="/adm/lonIcons/'.$icon.'";'); -} - -1; - __END__ =pod =back -=over 4 - -=head1 HANDLER SUBROUTINE - -This routine is called by Apache and mod_perl. - -=over 4 - -=item * - -configure dynamic components of interface - -=item * - -determine current user - -=item * - -see if a search invocation should be done - -=item * - -else, begin building search interface to output - -=item * - -compute date selection boxes - -=item * - -compute customized metadata field - -=item * - -print screen - -=back - -=head1 OTHER SUBROUTINES - -=over 4 - -=item * - -get_unprocessed_cgi() : reads in critical name/value pairs that may have not -been processed and passed into %ENV by the web server - -=item * - -make_persistent() : makes a set of hidden HTML fields to make -SQL search interface information to be persistent - -=back - -WEB INTERFACE COMPONENT FUNCTIONS - -=over 4 - -=item * - -simpletextfield(name,value) : returns HTML formatted string for simple text -field - -=item * - -simplecheckbox(name,value) : returns HTML formatted string for simple -checkbox - -=item * - -searchphrasefield(title,name,value) : returns HTML formatted string for -a search expression phrase field - -=item * - -dateboxes(name, defaultmonth, defaultday, defaultyear) : returns HTML -formatted string for a calendar date - -=item * - -selectbox(title,name,value,%HASH=options) : returns HTML formatted string for -a selection box field - -=back - -SEARCH FUNCTIONS - -=over 4 - -=item * - -advancedsearch(server reference, environment reference) : perform a complex -multi-field logical query - -=item * - -basicsearch(server reference, environment reference) : perform a simple -single-field logical query - -=item * - -build_SQL_query(field name, logic) : builds a SQL query string from a -logical expression with AND/OR keywords - -=item * - -build_custommetadata_query(field_name, logic_statement) : builds a perl -regular expression from a logical expression with AND/OR keywords - -=item * - -recursive_SQL_query_build(field name, reverse notation expression) : -builds a SQL query string from a reverse notation expression -logical expression with AND/OR keywords - -=item * - -build_date_queries(cmonth1, cday1, cyear1, cmonth2, cday2, cyear2, -lmonth1, lday1, lyear1, lmonth2, lday2, lyear2) : -Builds a SQL logic query to check time/date entries. - -=back - -OUTPUTTING RESULTS FUNCTION - -=over 4 - -=item * - -output_results(output mode, server reference, environment reference, -reply list reference) : outputs results from search - -=back - -DIFFERENT WAYS TO VIEW METADATA RECORDS - -=over 4 - -=item * - -detailed_citation_view(ORDERED METADATA LIST FOR A RESULT OBJECT INSTANCE) : -see metadata viewing notes below - -=item * - -summary_view(ORDERED METADATA LIST FOR A RESULT OBJECT INSTANCE) : -see metadata viewing notes below - -=item * - -fielded_format_view(ORDERED METADATA LIST FOR A RESULT OBJECT INSTANCE) : -see metadata viewing notes below - -=item * - -xml_sgml_view(ORDERED METADATA LIST FOR A RESULT OBJECT INSTANCE) : -see metadata viewing notes below - -=back - - _____________________________________________________________________ - | * Metadata viewing notes | - | Output is a HTML-ified string. | - | Input arguments are title, author, subject, url, keywords, version, | - | notes, short abstract, mime, language, creation date, | - | last revision date, owner, copyright, hostname, httphost, and | - | extra custom metadata to show. | - --------------------------------------------------------------------- - -TEST CONDITIONAL FUNCTIONS - -=over 4 - -=item * - -filled(field) : determines whether a given field has been filled - -=back - -ERROR FUNCTIONS - -=over 4 - -=item * - -output_blank_field_error(server reference) : outputs a message saying that -more fields need to be filled in - -=item * - -output_date_error(server reference, error message) : - - -=back - =cut