--- loncom/interface/lonsearchcat.pm 2001/03/08 16:54:20 1.4
+++ loncom/interface/lonsearchcat.pm 2006/05/12 16:45:41 1.264
@@ -1,685 +1,3721 @@
-# The LearningOnline Network
+# The LearningOnline Network with CAPA
# Search Catalog
#
-# 03/08/2001 Scott Harrison
+# $Id: lonsearchcat.pm,v 1.264 2006/05/12 16:45:41 albertel Exp $
#
+# Copyright Michigan State University Board of Trustees
+#
+# This file is part of the LearningOnline Network with CAPA (LON-CAPA).
+#
+# LON-CAPA is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# LON-CAPA is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with LON-CAPA; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# /home/httpd/html/adm/gpl.txt
+#
+# http://www.lon-capa.org/
+#
+###############################################################################
+###############################################################################
+
+=pod
+
+=head1 NAME
+
+lonsearchcat - LONCAPA Search Interface
+
+=head1 SYNOPSIS
+
+Search interface to LON-CAPAs digital library
+
+=head1 DESCRIPTION
+
+This module enables searching for a distributed browseable catalog.
+
+This is part of the LearningOnline Network with CAPA project
+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 separate window.
+
+=head1 Internals
+
+=over 4
+
+=cut
+
+###############################################################################
+###############################################################################
+
package Apache::lonsearchcat;
use strict;
-use Apache::Constants qw(:common);
-
-my %language;
-my $scrout;
-my %metadatafields;
-my %cprtag;
-my %mimetag;
+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();
+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();
+
+######################################################################
+######################################################################
+##
+## 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);
+######################################################################
+######################################################################
sub handler {
my $r = shift;
- $r->content_type('text/html');
+# &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().
+
+ 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']);
+ ##
+ ## 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'}_searchcat.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;
+ }
- %metadatafields=();
+ my $persistent_db_file = "/home/httpd/perl/tmp/".
+ &Apache::lonnet::escape($domain).
+ '_'.&Apache::lonnet::escape($env{'user.name'}).
+ '_'.$env{'form.persistent_db_id'}.'_persistent_search.db';
+ ##
+ &Apache::lonhtmlcommon::clear_breadcrumbs();
+ if (exists($env{'request.course.id'}) && $env{'request.course.id'} ne '') {
+ &Apache::lonhtmlcommon::add_breadcrumb
+ ({href=>'/adm/searchcat?'.
+ 'catalogmode='.$env{'form.catalogmode'}.
+ '&launch='.$env{'form.launch'}.
+ '&mode='.$env{'form.mode'},
+ text=>"Course and Catalog Search",
+ target=>'_top',
+ bug=>'Searching',});
+ } else {
+ &Apache::lonhtmlcommon::add_breadcrumb
+ ({href=>'/adm/searchcat?'.
+ 'catalogmode='.$env{'form.catalogmode'}.
+ '&launch='.$env{'form.launch'}.
+ '&mode='.$env{'form.mode'},
+ text=>"Catalog Search",
+ 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 'groupsearch'))) {
+ 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');
+ }
+ ##
+ ## 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') {
+ &Apache::lonhtmlcommon::add_breadcrumb
+ ({href=>'/adm/searchcat?phase=disp_adv&'.
+ 'catalogmode='.$env{'form.catalogmode'}.
+ '&launch='.$env{'form.launch'}.
+ '&mode='.$env{'form.mode'},
+ text=>"Advanced 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);
+ } 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);
+ }
+ } 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())) {
+ 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;
+}
-# ------------------------------------------------ First, check out environment
- $metadatafields{'owner'}=$ENV{'user.name'}.'@'.$ENV{'user.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'} = '';
+ }
+ }
+}
-
- %language=();
- $language{'any'}='Any language';
- {
- my $fh=Apache::File->new($r->dir_config('lonTabDir').'/language.tab');
- map {
- $_=~/(\w+)\s+([\w\s\-]+)/;
- $language{$1}=$2;
- } <$fh>;
- }
-
- %cprtag=();
- $cprtag{'any'}='Any copyright/distribution';
- {
- my $fh=Apache::File->new($r->dir_config('lonIncludes').'/copyright.tab');
- map {
- $_=~/(\w+)\s+([\w\s\-]+)/;
- $cprtag{$1}=$2;
- } <$fh>;
- }
-
- %mimetag=();
- $mimetag{'any'}='Any type';
- {
- my $fh=Apache::File->new($r->dir_config('lonTabDir').'/filetypes.tab');
- map {
- $_=~/(\w+)\s+(\w+)\s+([\w\s\-]+)/;
- $mimetag{$1}=".$1 $3";
- } <$fh>;
- }
-
- $scrout="";
- $scrout.=&searchphrasefield('Limit by title','title',
- '');
-
- $scrout.=&searchphrasefield('Limit by author','author',
- '');
-
- $scrout.=&searchphrasefield('Limit by subject','subject',
- '');
-
- $scrout.=&searchphrasefield('Limit by notes','notes',
- '');
+sub hidden_field {
+ my ($name,$value) = @_;
+ if (! defined($value)) {
+ $value = $env{'form.'.$name};
+ }
+ return ''.$/;
+}
+
+######################################################################
+######################################################################
+##
+## 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').
+ '
'.
+ $pretty_search_string.'
'.
+ ''.&mt('Course content').': ');
+ $r->rflush();
+# ======================================================= Go through the course
+ my $c=$r->connection;
+ if (tie(%hash,'GDBM_File',$env{'request.course.fn'}.".db",
+ &GDBM_READER(),0640)) {
+ foreach (sort(keys(%hash))) {
+ if ($c->aborted()) { last; }
+ if (($_=~/^src\_(.+)$/)) {
+ if ($hash{'randomout_'.$1} & !$env{'request.role.adv'}) {
+ next;
+ }
+ my $symb=&make_symb($1);
+ &checkonthis($r,$1,$hash{$_},0,&Apache::lonnet::gettitle($symb),
+ $fulltext,$symb,@allwords);
+ }
+ }
+ untie(%hash);
+ }
+ unless ($totalfound) {
+ $r->print('
'.&mt('No matches found in resources').'.
');
+ }
- $scrout.=&searchphrasefield('Limit by abstract','abstract',
- '');
+# Check discussions if requested
+ if ($discuss) {
+ my $totaldiscussions = 0;
+ $r->print('
'.&mt('Discussion postings').': ');
+ my $navmap = Apache::lonnavmaps::navmap->new();
+ my @allres=$navmap->retrieveResources();
+ my %discussiontime = &Apache::lonnet::dump('discussiontimes',
+ $env{'course.'.$env{'request.course.id'}.'.domain'},
+ $env{'course.'.$env{'request.course.id'}.'.num'});
+ foreach my $resource (@allres) {
+ my $result = '';
+ my $applies = 0;
+ my $symb = $resource->symb();
+ my $ressymb = $symb;
+ if ($symb =~ m#(___adm/\w+/\w+)/(\d+)/bulletinboard$#) {
+ $ressymb = 'bulletin___'.$2.$1.'/'.$2.'/bulletinboard';
+ unless ($ressymb =~ m#bulletin___\d+___adm/wrapper#) {
+ $ressymb=~s#(bulletin___\d+___)#$1adm/wrapper/#;
+ }
+ }
+ if (defined($discussiontime{$ressymb})) {
+ my %contrib = &Apache::lonnet::restore($ressymb,$env{'request.course.id'},
+ $env{'course.'.$env{'request.course.id'}.'.domain'},
+ $env{'course.'.$env{'request.course.id'}.'.num'});
+ if ($contrib{'version'}) {
+ for (my $id=1;$id<=$contrib{'version'};$id++) {
+ unless (($contrib{'hidden'}=~/\.$id\./) || ($contrib{'deleted'}=~/\.$id\./)) {
+ if ($contrib{$id.':subject'}) {
+ $result .= $contrib{$id.':subject'};
+ }
+ if ($contrib{$id.':message'}) {
+ $result .= $contrib{$id.':message'};
+ }
+ if ($contrib{$id,':attachmenturl'}) {
+ if ($contrib{$id,':attachmenturl'} =~ m-/([^/]+)$-) {
+ $result .= $1;
+ }
+ }
+ $applies = &checkwords($result,$applies,@allwords);
+ }
+ }
+ }
+ }
+# Does this discussion apply?
+ if ($applies) {
+ my ($map,$ind,$url)=&Apache::lonnet::decode_symb($ressymb);
+ my $disctype = &mt('resource');
+ if ($url =~ m#/bulletinboard$#) {
+ if ($url =~m#^adm/wrapper/adm/.*/bulletinboard$#) {
+ $url =~s#^adm/wrapper##;
+ }
+ $disctype = &mt('bulletin board');
+ } else {
+ $url = '/res/'.$url;
+ }
+ if ($url =~ /\?/) {
+ $url .= '&symb=';
+ } else {
+ $url .= '?symb=';
+ }
+ $url .= &Apache::lonnet::escape($resource->symb());
+ my $title = $resource->compTitle();
+ $r->print(' '.
+ ($title?$title:$url).' - '.$disctype.' ');
+ $totaldiscussions++;
+ } else {
+ $r->print(' .');
+ }
+ }
+ unless ($totaldiscussions) {
+ $r->print('
'.&mt('No matches found in postings').'.
');
+ }
+ }
+
+# =================================================== Done going through course
+ $r->print(&Apache::loncommon::end_page());
+}
- $scrout.=&selectbox('Limit by MIME type','mime',
- 'notxxx',%mimetag);
+# =============================== This pulls up a resource and its dependencies
- $scrout.=&selectbox('Limit by language','language',
- 'any',%language);
+sub checkonthis {
+ my ($r,$id,$url,$level,$title,$fulltext,$symb,@allwords)=@_;
+ $alreadyseen{$id}=1;
+ if (&Apache::loncommon::connection_aborted($r)) { return; }
+ $r->rflush();
- $scrout.=<print(' ');
+ for (my $i=0;$i<=$level*5;$i++) {
+ $r->print(' ');
+ }
+ my $href=$url;
+ if ($hash{'encrypted_'.$id} && !$env{'request.role.adv'}) {
+ $href=&Apache::lonenc::encrypted($href)
+ .'?symb='.&Apache::lonenc::encrypted($symb);
+ } else {
+ $href.='?symb='.&Apache::lonnet::escape($symb);
+ }
+ $r->print(''.($title?$title:$url).
+ ' ');
+ $totalfound++;
+ } elsif ($fulltext) {
+ $r->print(' .');
+ }
+ $r->rflush();
+# Check also the dependencies of this one
+ my $dependencies=
+ &Apache::lonnet::metadata($url,'dependencies');
+ foreach (split(/\,/,$dependencies)) {
+ if (($_=~/^\/res\//) && (!$alreadyseen{$id})) {
+ &checkonthis($r,$id,$_,$level+1,'',$fulltext,undef,@allwords);
+ }
+ }
+}
+
+sub checkwords {
+ my ($result,$applies,@allwords) = @_;
+ foreach (@allwords) {
+ if ($_=~/\w/) {
+ if ($result=~/$_/si) {
+ $applies++;
+ }
+ }
+ }
+ return $applies;
+}
+
+sub untiehash {
+ if (tied(%hash)) {
+ untie(%hash);
+ }
+}
+
+} # End of course search scoping
+
+
+######################################################################
+######################################################################
+
+=pod
+
+=item &print_basic_search_form()
+
+Prints the form for the basic search. Sorry the name is so cryptic.
+
+=cut
+
+######################################################################
+######################################################################
+sub print_basic_search_form {
+ my ($r,$closebutton,$hidden_fields) = @_;
+ my $result = ($env{'form.catalogmode'} ne 'groupsearch');
+ my $bread_crumb =
+ &Apache::lonhtmlcommon::breadcrumbs('Searching','Search_Basic',
+ $env{'form.catalogmode'} ne 'groupsearch');
+ my $scrout = &Apache::loncommon::start_page('Search').$bread_crumb;
+ if (&Apache::lonnet::allowed('bre',$env{'request.role.domain'})) {
+ # Define interface components
+ my $userelatedwords= '';
+ my $onlysearchdomain='';
+ my $inclext= '';
+ my $adv_search_link =
+ ''.&mt('Advanced Search').'';
+ #
+ $scrout.='';
+ }
+ if ($env{'request.course.id'}) {
+ my %lt=&Apache::lonlocal::texthash('srch' => 'Search',
+ 'header' => 'Course Search',
+ 'note' => 'Enter terms or phrases, then press "Search" below',
+ 'use' => 'use related words',
+ 'full' =>'fulltext search (time consuming)',
+ 'disc' => 'search discussion postings (resources and bulletin boards)',
+ );
+ $scrout.=(<
+
'.
+ mt('Results [_1] to [_2] out of [_3]',
+ $min,$max,$total_results).
+ "
\n");
+ }
+ ##
+ ## Get results from MySQL table
+ my $sort_command = 'id>='.$min.' AND id<='.$max;
+ my $order;
+ if (exists($env{'form.sortorder'})) {
+ if ($env{'form.sortorder'} eq 'asc') {
+ $order = 'ASC';
+ } elsif ($env{'form.sortorder'} eq 'desc') {
+ $order = 'DESC';
+ } else {
+ $order = '';
+ }
+ } else {
+ $order = '';
+ }
+ if ($env{'form.sortfield'} ne 'default' &&
+ exists($sort_fields{$env{'form.sortfield'}})) {
+ $sort_command = $env{'form.sortfield'}.' IS NOT NULL '.
+ 'ORDER BY '.$env{'form.sortfield'}.' '.$order.
+ ' LIMIT '.($min-1).','.($max-$min+1);
+ }
+ my @Results = &Apache::lonmysql::get_rows($table,$sort_command);
+ ##
+ ## Loop through the results and output them.
+ foreach my $row (@Results) {
+ if ($connection->aborted()) {
+ &cleanup();
+ return;
+ }
+ my %Fields = %{&parse_row(@$row)};
+ my $output="
\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
+ ('
-
+=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,$closebutton,$parms,$hidden_fields)=@_;
+ my $errormsg = &mt('You did not fill in enough information for the search to be started. You need to fill in relevant fields on the search page in order for a query to be processed.');
+ my $revise = &mt('Revise Search Request');
+ my $heading = &mt('Unactionable Search Queary');
+ my $start_page = &Apache::loncommon::start_page('Search');
+ my $end_page = &Apache::loncommon::end_page();
+ $r->print(<
-
-
Basic Search
+$hidden_fields
+$closebutton
+
+
$heading
-Enter terms or phrases separated by search operators
-such as AND or OR then press SEARCH below. Terms should be specific
-to the title, author, subject, notes, or abstract information associated
-with a resource.
-
-
-
-Title only
-
-
+$errormsg