Diff for /loncom/interface/lonsearchcat.pm between versions 1.153 and 1.320

version 1.153, 2002/08/16 13:52:51 version 1.320, 2010/02/13 01:12:16
Line 48  described at http://www.lon-capa.org. Line 48  described at http://www.lon-capa.org.
 lonsearchcat presents the user with an interface to search the LON-CAPA  lonsearchcat presents the user with an interface to search the LON-CAPA
 digital library.  lonsearchcat also initiates the execution of a search  digital library.  lonsearchcat also initiates the execution of a search
 by sending the search parameters to LON-CAPA servers.  The progress of   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  =head1 Internals
   
Line 59  search (on a server basis) is displayed Line 59  search (on a server basis) is displayed
 ###############################################################################  ###############################################################################
 ###############################################################################  ###############################################################################
   
 ###############################################################################  
 ##                                                                           ##  
 ## ORGANIZATION OF THIS PERL MODULE                                          ##  
 ##                                                                           ##  
 ## 1. Modules used by this module                                            ##  
 ## 2. Variables used throughout the module                                   ##  
 ## 3. handler subroutine called via Apache and mod_perl                      ##  
 ## 4. Other subroutines                                                      ##  
 ##                                                                           ##  
 ###############################################################################  
   
 package Apache::lonsearchcat;  package Apache::lonsearchcat;
   
 # ------------------------------------------------- modules used by this module  
 use strict;  use strict;
 use Apache::Constants qw(:common);  use Apache::Constants qw(:common :http);
 use Apache::lonnet();  use Apache::lonnet;
 use Apache::File();  use Apache::File();
 use CGI qw(:standard);  use CGI qw(:standard);
 use Text::Query;  use Text::Query;
 use DBI;  
 use GDBM_File;  use GDBM_File;
 use Apache::loncommon();  use Apache::loncommon();
 use Apache::lonmysql();  use Apache::lonmysql();
   use Apache::lonmeta;
 # ---------------------------------------- variables used throughout the module  use Apache::lonhtmlcommon;
   use Apache::lonlocal;
 ######################################################################  use LONCAPA::lonmetadata();
 ######################################################################  use HTML::Entities();
   use Parse::RecDescent;
 =pod   use Apache::lonnavmaps;
   use Apache::lonindexer();
 =item Global variables  use LONCAPA;
   
 =over 4  
   
 =item $importbutton  
   
 button to take the select results and go to group sorting  
   
 =item %groupsearch_db     
   
 Database hash used to save values for the groupsearch RAT interface.  
   
 =item $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 %Views  
   
 Hash which associates an output view description with the function  
 that produces it.  Adding a new view type should be as easy as  
 adding a line to the definition of this hash and making sure the function  
 takes the proper parameters.  
   
 =back   
   
 =cut  
   
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
   ##
 # -- dynamically rendered interface components  ## Global variables
 my $importbutton; # button to take the selected results and go to group sorting  ##
   
 # -- miscellaneous variables  
 my %groupsearch_db;     # database hash  
 my $diropendb = "";    # db file  
 #             View Description           Function Pointer  
 my %Views = ("Detailed Citation View" => \&detailed_citation_view,  
              "Summary View"           => \&summary_view,  
              "Fielded Format"         => \&fielded_format_view,  
              "XML/SGML"               => \&xml_sgml_view,  
              "Compact View"           => \&compact_view);  
 my %persistent_db;  
 my $hidden_fields;  
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
   my %groupsearch_db;  # Database hash used to save values for the 
 =pod                        # groupsearch RAT interface.
   my %persistent_db;   # gdbm hash which holds data which is supposed to
 =item &handler() - main handler invoked by httpd child                       # persist across calls to lonsearchcat.pm
   
 =item Variables  # The different view modes and associated functions
   
 =over 4  my %Views = ("detailed" => \&detailed_citation_view,
                "detailedpreview" => \&detailed_citation_preview,
 =item $hidden       "summary"  => \&summary_view,
                "summarypreview" => \&summary_preview,
 holds 'hidden' html forms       "fielded"  => \&fielded_format_view,
        "xml"      => \&xml_sgml_view,
 =item $scrout       "compact"  => \&compact_view);
   
 string that holds portions of the screen output  
   
 =back   
   
 =cut  
   
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
 sub handler {  sub handler {
     my $r = shift;      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().
   
       my $loaderror=&Apache::lonnet::overloaderror($r);
       if ($loaderror) { return $loaderror; }
     #      #
     my $closebutton;  # button that closes the search window       my $closebutton;  # button that closes the search window 
                       # This button is different for the RAT compared to                        # This button is different for the RAT compared to
                       # normal invocation.                        # normal invocation.
     #      #
     $r->content_type('text/html');      &Apache::loncommon::content_type($r,'text/html');
     $r->send_http_header;      $r->send_http_header;
     return OK if $r->header_only;      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.      ## Pick up form fields passed in the links.
     ##      ##
     &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},      &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
              ['catalogmode','launch','acts','mode','form','element','pause',               ['catalogmode','launch','acts','mode','form','element','pause',
               'phase','persistent_db_id','table','start','show']);                'phase','persistent_db_id','table','start','show',
                 'cleargroupsort','titleelement','area','inhibitmenu']);
     ##      ##
     ## The following is a trick - we wait a few seconds if asked to so      ## 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      ##     the daemon running the search can get ahead of the daemon
     ##     printing the results.  We only need (theoretically) to do      ##     printing the results.  We only need (theoretically) to do
     ##     this once, so the pause indicator is deleted      ##     this once, so the pause indicator is deleted
     ##      ##
     if (exists($ENV{'form.pause'})) {      if (exists($env{'form.pause'})) {
         sleep(3);          sleep(1);
         delete($ENV{'form.pause'});          delete($env{'form.pause'});
     }      }
     ##      ##
     ## Initialize global variables      ## Initialize global variables
     ##      ##
     my $domain  = $r->dir_config('lonDefDomain');      my $domain  = $r->dir_config('lonDefDomain');
     $diropendb= "/home/httpd/perl/tmp/".&Apache::lonnet::escape($domain).      $diropendb= "/home/httpd/perl/tmp/".
             "\_".&Apache::lonnet::escape($ENV{'user.name'})."_searchcat.db";          "$env{'user.domain'}_$env{'user.name'}_sel_res.db";
     #      #
     # set the name of the persistent database      # set the name of the persistent database
     #          $ENV{'form.persistent_db_id'} can only have digits in it.      #          $env{'form.persistent_db_id'} can only have digits in it.
     if (! exists($ENV{'form.persistent_db_id'}) ||      if (! exists($env{'form.persistent_db_id'}) ||
         ($ENV{'form.persistent_db_id'} =~ /\D/) ||          ($env{'form.persistent_db_id'} =~ /\D/) ||
         ($ENV{'form.launch'} eq '1')) {          ($env{'form.launch'} eq '1')) {
         $ENV{'form.persistent_db_id'} = time;          $env{'form.persistent_db_id'} = time;
     }      }
   
     my $persistent_db_file = "/home/httpd/perl/tmp/".      my $persistent_db_file = "/home/httpd/perl/tmp/".
         &Apache::lonnet::escape($domain).          &escape($domain).
             '_'.&Apache::lonnet::escape($ENV{'user.name'}).              '_'.&escape($env{'user.name'}).
                 '_'.$ENV{'form.persistent_db_id'}.'_persistent_search.db';                  '_'.$env{'form.persistent_db_id'}.'_persistent_search.db';
     ##      ##
     if (! &get_persistent_form_data($persistent_db_file)) {      &Apache::lonhtmlcommon::clear_breadcrumbs();
         if ($ENV{'form.phase'} =~ /(run_search|results)/) {  
             &Apache::lonnet::logthis("lonsearchcat:Unable to recover data ".      my @allowed_searches = ('portfolio');
                                      "from $persistent_db_file");      if (&Apache::lonnet::allowed('bre',$env{'request.role.domain'})) {
             $r->print(<<END);          push(@allowed_searches,'res');
 <html>      } 
 <head><title>LON-CAPA Search Error</title></head>      if (exists($env{'request.course.id'}) && $env{'request.course.id'} ne '') {
 <body>          push(@allowed_searches,'course');
 We were unable to retrieve data describing your search.  This is a serious      }
 error and has been logged.  Please alert your LON-CAPA administrator.      my $crumb_text = 'Portfolio Search';
 </body>      if (@allowed_searches == 3) {
 </html>          $crumb_text = 'Course, Portfolio and Catalog Search';
 END      } elsif (@allowed_searches ==2) {
             return OK;          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?'.
          &Apache::loncommon::inhibit_menu_check().
                  '&amp;catalogmode='.$env{'form.catalogmode'}.
                  '&amp;launch='.$env{'form.launch'}.
                  '&amp;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      ## Clear out old values from groupsearch database
     ##      ##
     untie %groupsearch_db if (tied(%groupsearch_db));      untie %groupsearch_db if (tied(%groupsearch_db));
     if ($ENV{'form.launch'} eq '1' &&       if (($env{'form.cleargroupsort'} eq '1') || 
         ($ENV{'form.catalogmode'} eq 'groupsearch') &&           (($env{'form.launch'} eq '1') && 
         ($ENV{'form.phase'} eq 'results')) {           ($env{'form.catalogmode'} eq 'import'))) {
  if (tie(%groupsearch_db,'GDBM_File',$diropendb,&GDBM_WRCREAT(),0640)) {   if (tie(%groupsearch_db,'GDBM_File',$diropendb,&GDBM_WRCREAT(),0640)) {
     &start_fresh_session();      &start_fresh_session();
     untie %groupsearch_db;      untie %groupsearch_db;
               delete($env{'form.cleargroupsort'});
  } else {   } else {
     $r->print('<html><head></head><body>Unable to tie hash to db '.              # This is a stupid error to give to the user.  
       'file</body></html>');              # 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;      return OK;
  }   }
     }      }
Line 242  END Line 240  END
     ## Configure hidden fields      ## Configure hidden fields
     ##      ##
     $hidden_fields = '<input type="hidden" name="persistent_db_id" value="'.      $hidden_fields = '<input type="hidden" name="persistent_db_id" value="'.
         $ENV{'form.persistent_db_id'}.'" />'."\n";          $env{'form.persistent_db_id'}.'" />'."\n";
     if (exists($ENV{'form.catalogmode'})) {      if (exists($env{'form.catalogmode'})) {
         $hidden_fields .= '<input type="hidden" name="catalogmode" value="'.          $hidden_fields .= &hidden_field('catalogmode');
                 $ENV{'form.catalogmode'}.'" />'."\n";      }
     }      if (exists($env{'form.form'})) {
     if (exists($ENV{'form.form'})) {          $hidden_fields .= &hidden_field('form');
         $hidden_fields .= '<input type="hidden" name="form" value="'.      }
                 $ENV{'form.form'}.'" />'."\n";      if (exists($env{'form.element'})) {
     }          $hidden_fields .= &hidden_field('element');
     if (exists($ENV{'form.element'})) {      }
         $hidden_fields .= '<input type="hidden" name="element" value="'.      if (exists($env{'form.titleelement'})) {
                 $ENV{'form.element'}.'" />'."\n";          $hidden_fields .= &hidden_field('titleelement');
     }      }
     if (exists($ENV{'form.mode'})) {      if (exists($env{'form.mode'})) {
         $hidden_fields .= '<input type="hidden" name="mode" value="'.          $hidden_fields .= &hidden_field('mode');
                 $ENV{'form.mode'}.'" />'."\n";      }
       if (exists($env{'form.area'})) {
           $hidden_fields .= &hidden_field('area');
       }
       if (exists($env{'form.inhibitmenu'})) {
           $hidden_fields .= &hidden_field('inhibitmenu');
     }      }
     ##      ##
     ## Configure dynamic components of interface      ## Configure dynamic components of interface
     ##      ##
     if ($ENV{'form.catalogmode'} eq 'interactive') {      if ($env{'form.catalogmode'} eq 'interactive') {
         $closebutton="<input type='button' name='close' value='CLOSE' ";          $closebutton="<input type='button' name='close' value='".&mt('Close')."' ";
         if ($ENV{'form.phase'} =~ /(results|run_search)/) {          if ($env{'form.phase'} =~ /(results|run_search)/) {
     $closebutton .="onClick='parent.close()'";              $closebutton .="onclick='parent.close()'";
         } else {          } else {
             $closebutton .="onClick='self.close()'";              $closebutton .="onclick='self.close()'";
         }          }
         $closebutton .=">\n";          $closebutton .=" />\n";
     } elsif ($ENV{'form.catalogmode'} eq 'groupsearch') {      } elsif ($env{'form.catalogmode'} eq 'import') {
         $closebutton="<input type='button' name='close' value='CLOSE' ";          $closebutton="<input type='button' name='close' value='".&mt('Close')."' ";
         if ($ENV{'form.phase'} =~ /(results|run_search)/) {          if ($env{'form.phase'} =~ /(results|run_search)/) {
     $closebutton .="onClick='parent.close()'";              $closebutton .="onclick='parent.close()'";
         } else {          } else {
             $closebutton .="onClick='self.close()'";              $closebutton .="onclick='self.close()'";
         }          }
         $closebutton .= ">";          $closebutton .= " />";
           my $txt_import = &mt('IMPORT');
         $importbutton=<<END;          $importbutton=<<END;
 <input type='button' name='import' value='IMPORT'  <input type='button' name='import' value='$txt_import'
 onClick='javascript:select_group()'>  onclick='javascript:select_group()' />
 END  END
     } else {      } else {
         $closebutton = '';          $closebutton = '';
Line 289  END Line 293  END
     ##      ##
     ## Sanity checks on form elements      ## Sanity checks on form elements
     ##      ##
     if (!defined($ENV{'form.viewselect'})) {      if (!defined($env{'form.viewselect'})) {
         if (($ENV{'form.catalogmode'} eq 'groupsearch') ||   $env{'form.viewselect'} ="summary";
             ($ENV{'form.catalogmode'} eq 'interactive')) {      }
             $ENV{'form.viewselect'} ="Compact View";      $env{'form.phase'} = 'disp_basic' if (! exists($env{'form.phase'}));
         } else {      $env{'form.show'} = 20 if (! exists($env{'form.show'}));
             $ENV{'form.viewselect'} ="Detailed Citation View";      #
         }      $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?'.&Apache::loncommon::inhibit_menu_check().
                     '&amp;phase=disp_adv'.
                     '&amp;catalogmode='.$env{'form.catalogmode'}.
                     '&amp;launch='.$env{'form.launch'}.
                     '&amp;mode='.$env{'form.mode'},
                     text=>"Advanced $srchtype Search",
                     bug=>'Searching',});
       } elsif ($env{'form.searchmode'} eq 'course search') {
           &Apache::lonhtmlcommon::add_breadcrumb
               ({href=>'/adm/searchcat?'.&Apache::loncommon::inhibit_menu_check().
                     '&amp;phase=disp_adv'.
                     '&amp;catalogmode='.$env{'form.catalogmode'}.
                     '&amp;launch='.$env{'form.launch'}.
                     '&amp;mode='.$env{'form.mode'},
                     text=>"Course Search",
                     bug=>'Searching',});
     }      }
     $ENV{'form.phase'} = 'disp_basic' if (! exists($ENV{'form.phase'}));  
     $ENV{'form.show'} = 20 if (! exists($ENV{'form.show'}));  
     ##      ##
     ## Switch on the phase      ## Switch on the phase
     ##      ##
     if ($ENV{'form.phase'} eq 'disp_basic') {      if ($env{'form.phase'} eq 'disp_basic') {
         &print_basic_search_form($r,$closebutton);          &print_basic_search_form($r,$closebutton,$hidden_fields);
     } elsif ($ENV{'form.phase'} eq 'disp_adv') {      } elsif ($env{'form.phase'} eq 'disp_adv') {
         &print_advanced_search_form($r,$closebutton);          &print_advanced_search_form($r,$closebutton,$hidden_fields);
     } elsif ($ENV{'form.phase'} eq 'results') {      } elsif ($env{'form.phase'} eq 'results') {
         &display_results($r,$importbutton,$closebutton);          &display_results($r,$importbutton,$closebutton,$diropendb,
     } elsif ($ENV{'form.phase'} =~ /^(sort|run_search)$/) {                           $env{'form.area'});
       } elsif ($env{'form.phase'} =~ /^(sort|run_search)$/) {
         my ($query,$customquery,$customshow,$libraries,$pretty_string) =          my ($query,$customquery,$customshow,$libraries,$pretty_string) =
             &get_persistent_data($persistent_db_file,              &get_persistent_data($persistent_db_file,
                  ['query','customquery','customshow',                   ['query','customquery','customshow',
                   'libraries','pretty_string']);                    'libraries','pretty_string']);
         if ($ENV{'form.phase'} eq 'sort') {          if ($env{'form.phase'} eq 'sort') {
             &print_sort_form($r,$pretty_string);              &print_sort_form($r,$pretty_string);
         } elsif ($ENV{'form.phase'} eq 'run_search') {          } elsif ($env{'form.phase'} eq 'run_search') {
             &run_search($r,$query,$customquery,$customshow,              &run_search($r,$query,$customquery,$customshow,
                         $libraries,$pretty_string);                          $libraries,$pretty_string,$env{'form.area'});
         }  
     } elsif(($ENV{'form.phase'} eq 'basic_search') ||  
             ($ENV{'form.phase'} eq 'adv_search')) {  
         $ENV{'form.searchmode'} = 'basic';  
         if ($ENV{'form.phase'} eq 'adv_search') {  
             $ENV{'form.searchmode'} = 'advanced';  
         }  
         # Set up table  
         if (! defined(&create_results_table())) {  
             $r->print(<<END);  
 <html><head><title>Search Error</title></head>  
 <body>  
 Unable to create table in which to store search results.    
 The search has been aborted.  
 </body>  
 </html>  
 END  
             return OK;  
         }  
         delete($ENV{'form.launch'});  
         if (! &make_form_data_persistent($r,$persistent_db_file)) {  
             $r->print(<<END);  
 <html><head><title>Search Error</title></head>  
 <body>  
 Unable to properly store search information.  The search has been aborted.  
 </body>  
 </html>  
 END  
             return OK;  
         }          }
       } 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          # We are running a search, try to parse it
         my ($query,$customquery,$customshow,$libraries) =           my ($query,$customquery,$customshow,$libraries) = 
             (undef,undef,undef,undef);              (undef,undef,undef,undef);
         my $pretty_string;          my $pretty_string;
         if ($ENV{'form.phase'} eq 'basic_search') {          if ($env{'form.phase'} eq 'basic_search') {
             ($query,$pretty_string) = &parse_basic_search($r,$closebutton);              ($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          } else {                      # Advanced search
             ($query,$customquery,$customshow,$libraries,$pretty_string)               ($query,$customquery,$customshow,$libraries,$pretty_string) 
                 = &parse_advanced_search($r,$closebutton);                  = &parse_advanced_search($r,$closebutton,$hidden_fields);
             return OK if (! defined($query));              return OK if (! defined($query));
         }          }
         &make_persistent({ query => $query,          &make_persistent({ query => $query,
Line 366  END Line 377  END
                            libraries => $libraries,                             libraries => $libraries,
                            pretty_string => $pretty_string },                             pretty_string => $pretty_string },
                          $persistent_db_file);                           $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 save 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 save search information. '.
    'The search has been aborted.';
       &Apache::loncommon::simple_error_page($r,'Search Error',
     $msg);
       return OK;
    }
         ##          ##
         ## Print out the frames interface          ## Print out the frames interface
         ##          ##
         &print_frames_interface($r);          if (defined($query)) {
               &print_frames_interface($r);
           }
     }      }
     return OK;      return OK;
 }   } 
   
   #
   # 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'} = '';
           }
       }
   }
   
   sub hidden_field {
       my ($name,$value) = @_;
       if (! defined($value)) {
           $value = $env{'form.'.$name};
       }
       return '<input type="hidden" name="'.$name.'" value="'.$value.'" />'.$/;
   }
   
   ######################################################################
   ######################################################################
   ##
   ##   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 = '<b>'.$env{'form.courseexp'}.'</b>';
       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").": <b>@New_Words</b>.";
           } 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;
   
       &Apache::lonhtmlcommon::add_breadcrumb
           ({href=>'/adm/searchcat?'.&Apache::loncommon::inhibit_menu_check().
                 '&amp;phase=disp_adv'.
                 '&amp;catalogmode='.$env{'form.catalogmode'}.
                 '&amp;launch='.$env{'form.launch'}.
                 '&amp;mode='.$env{'form.mode'},
                 text=>"Course Search",
                 bug=>'Searching',});
       $r->print(&Apache::loncommon::start_page('Course Search'));
       $r->print(&Apache::lonhtmlcommon::breadcrumbs('Searching','Searching',
                           $env{'form.catalogmode'} ne 'import'));
   
       $r->print(
         '<hr /><center><font size="+2" face="arial">'.
         $pretty_search_string.'</font></center>'.
         '<hr /><b>'.&mt('Course content').':</b><br />');
       $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('<p class="LC_info">'.&mt('No matches found in resources.').'</p>');
       }
   
   # Check discussions if requested
       if ($discuss) {
           my $totaldiscussions = 0;
           $r->print('<br /><br /><b>'.&mt('Discussion postings').':</b><br />'); 
           my $navmap = Apache::lonnavmaps::navmap->new();
           if (defined($navmap)) {
               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/$LONCAPA::domain_re/$LONCAPA::username_re)/(\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('discussion board');
                       } else {
                           $url = '/res/'.$url;
                       }
                       if ($url =~ /\?/) {
                           $url .= '&amp;symb=';
                       } else {
                           $url .= '?symb=';
                       }
                       $url .= &escape($resource->symb());
                       my $title = $resource->compTitle();
                       $r->print('<br /><a href="'.$url.'" target="cat">'.
                            ($title?$title:$url).'</a>&nbsp;&nbsp;-&nbsp;'.
                            $disctype.'<br />');
                       $totaldiscussions++;
                   } else {
                       $r->print(' .');
                   }
               }
               unless ($totaldiscussions) {
                   $r->print('<p class="LC_info">'.&mt('No matches found in postings.').'</p>');
               }
           } else {
               $r->print('<div class="LC_error">'.&mt('An error occurred retrieving information about resources in the course.').'<br />'.&mt('It is recommended that you [_1]re-initialize the course[_2] and then try your search again.','<a href="/adm/roles">','</a>').'</div>');
           }
       }
    
   # =================================================== Done going through course
       $r->print(&Apache::loncommon::end_page());
   }
   
   # =============================== This pulls up a resource and its dependencies
   
   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('<br />');
          for (my $i=0;$i<=$level*5;$i++) {
              $r->print('&nbsp;');
          }
          my $href=$url;
          if ($hash{'encrypted_'.$id} && !$env{'request.role.adv'}) {
      $href=&Apache::lonenc::encrypted($href)
          .'?symb='.&Apache::lonenc::encrypted($symb);
          } else {
      $href.='?symb='.&escape($symb);
          }
          $r->print('<a href="'.$href.'" target="cat">'.($title?$title:$url).
    '</a><br />');
          $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
   
   
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
   
Line 381  END Line 691  END
   
 =item &print_basic_search_form()   =item &print_basic_search_form() 
   
 Returns a scalar which holds html for the basic search form.  Prints the form for the basic search.  Sorry the name is so cryptic.
   
 =cut  =cut
   
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
   sub print_basic_search_form {
 sub print_basic_search_form{      my ($r,$closebutton,$hidden_fields) = @_;
     my ($r,$closebutton) = @_;      my $result = ($env{'form.catalogmode'} ne 'import');
     my $scrout=<<"ENDDOCUMENT";      my $bread_crumb =
 <html>          &Apache::lonhtmlcommon::breadcrumbs('Searching','Search_Basic',
 <head>      $env{'form.catalogmode'} ne 'import');
 <title>The LearningOnline Network with CAPA</title>      my $scrout = &Apache::loncommon::start_page('Content Library').$bread_crumb;
 <script type="text/javascript">  # Search form for resource space 
     function openhelp(val) {      if (&Apache::lonnet::allowed('bre',$env{'request.role.domain'})) {
  openhelpwin=open('/adm/help/searchcat.html','helpscreen',          $scrout .= &setup_basic_search($r,'res',$hidden_fields,$closebutton);
      'scrollbars=1,width=600,height=300');          $scrout .= '<hr /><br />';
  openhelpwin.focus();      }
     }  # Search form for accessible portfolio files
 </script>      $scrout.= &setup_basic_search($r,'portfolio',$hidden_fields,$closebutton);
 </head>      if ($env{'request.course.id'}) {
 <body bgcolor="#FFFFFF">   my %lt=&Apache::lonlocal::texthash('srch' => 'Search',
 <img align='right' src='/adm/lonIcons/lonlogos.gif' />                                             'header' => 'Course Search',
 <h1>Search Catalog</h1>   'note' => 'Enter terms or phrases, then press "Search" below',
 <form method="post" action="/adm/searchcat">   'use' => 'use related words',
 <input type="hidden" name="phase" value="basic_search" />   'full' =>'fulltext search (time consuming)',
            'disc' => 'search discussion postings (resources and discussion boards)',
      );
           $scrout.=(<<ENDCOURSESEARCH);
   <form name="loncapa_search" method="post" action="/adm/searchcat">
   <center>
   <hr />
   <h1>$lt{'header'}</h1>    
   <input type="hidden" name="phase" value="course_search" />
 $hidden_fields  $hidden_fields
 <h3>Basic Search</h3>  
 <p>  <p>
 Enter terms or phrases separated by AND, OR, or NOT   $lt{'note'}.
 then press SEARCH below.  
 </p>  </p>
 <p>  
 <table>  <table>
 <tr><td>  <tr><td>
 ENDDOCUMENT  ENDCOURSESEARCH
     $scrout.='&nbsp;'.&simpletextfield('basicexp',$ENV{'form.basicexp'},40).          $scrout.='&nbsp;'.
         '&nbsp;';              &Apache::lonhtmlcommon::textbox('courseexp',
     my $checkbox = &simplecheckbox('related',$ENV{'form.related'});                                    $env{'form.courseexp'},40);
     $scrout.=<<END;          my $crscheckbox = 
 </td><td><a href="/adm/searchcat?phase=disp_adv">Advanced Search</a></td></tr>              &Apache::lonhtmlcommon::checkbox('crsfulltext',
 <tr><td>$checkbox use related words</td><td></td></tr>                                     $env{'form.crsfulltext'});
           my $relcheckbox = 
               &Apache::lonhtmlcommon::checkbox('crsrelated',
      $env{'form.crsrelated'});
           my $discheckbox = 
               &Apache::lonhtmlcommon::checkbox('crsdiscuss',
                                      $env{'form.crsrelated'});
           $scrout.=(<<ENDENDCOURSE);
   </td></tr>
   <tr><td><label>$relcheckbox $lt{'use'}</label></td><td></td></tr>
   <tr><td><label>$crscheckbox $lt{'full'}</label></td><td></td></tr>
   <tr><td><label>$discheckbox $lt{'disc'}</label></td><td></td></tr>
 </table>  </table>
 </p>  
 <p>  <p>
 &nbsp;<input type="submit" name="basicsubmit" value='SEARCH' />&nbsp;  <input type="submit" name="coursesubmit" value='$lt{'srch'}' />
 $closebutton  
 END  
     $scrout.=&selectbox(undef,'viewselect',  
  $ENV{'form.viewselect'},  
  undef,undef,undef,  
  sort(keys(%Views)));  
     $scrout.=&selectbox(undef,'show',  
  $ENV{'form.show'},  
  undef,undef,undef,  
  (10,20,50,100));  
     $scrout.=<<ENDDOCUMENT;  
 per page.  
 </p>  </p>
   </center>
 </form>  </form>
 </body>  ENDENDCOURSE
 </html>      }
 ENDDOCUMENT      $scrout .= &Apache::loncommon::end_page();
     $r->print($scrout);      $r->print($scrout);
     return;      return;
 }  }
   
   sub setup_basic_search {
       my ($r,$area,$hidden_fields,$closebutton) = @_;
       # Define interface components
       my %lt = &Apache::lonlocal::texthash (
                                 res => 'LON-CAPA Catalog Search',
                                 portfolio => 'Portfolio Search',
       );
       my ($userelatedwords,$onlysearchdomain,$inclext,$adv_search_link,$scrout);
   
       $userelatedwords = '<label>'
                         .&Apache::lonhtmlcommon::checkbox(
                              'related',
                              $env{'form.related'},
                              'related')
                         .' '
                        .&mt('use related words')
                        .'</label>';
   
       $onlysearchdomain = '<label>'
                          .&Apache::lonhtmlcommon::checkbox(
                              'domains',
                              $env{'form.domains'},
                              $r->dir_config('lonDefDomain'))
                          .' '
                          .&mt('only search domain [_1]'
                                  ,'<b>'.$r->dir_config('lonDefDomain').'</b>')
                          .'</label>';
   
       $adv_search_link = '<a href="/adm/searchcat?'.
                  &Apache::loncommon::inhibit_menu_check().
          '&amp;phase=disp_adv'.
                          '&amp;catalogmode='.$env{'form.catalogmode'}.
                          '&amp;launch='.$env{'form.launch'}.
                          '&amp;mode='.$env{'form.mode'}.
                          '&amp;area='.$area.
                          '&amp;form='.$env{'form.form'}.
                          '&amp;titleelement='.$env{'form.titleelement'}.
                          '&amp;element='.$env{'form.element'}.
                          '">'.&mt('Advanced Search').'</a>';
       #
       $scrout.='<form name="loncapa_search" method="post" '.
                'action="/adm/searchcat">'.
                '<input type="hidden" name="phase" value="basic_search" />'.
                $hidden_fields;
                if (!exists($env{'form.area'})) {
                    $scrout .= '<input type="hidden" name="area" value="'.$area.'" />';
                }
       #
       $scrout .= '<div align="center">'.$/;
   #    if ($env{'request.course.id'}) {
           $scrout .= '<h1>'.$lt{$area}.'</h1>';
   #    } else {
           # No need to tell them they are searching
   #        $scrout.= ('<br />'x2);
   #    }
       $scrout.='<table>'.
                '<tr><td align="center" valign="top">'.
                &Apache::lonhtmlcommon::textbox('basicexp',
                                                $env{'form.basicexp'},50).
                '<br />'.
               '<span class="LC_fontsize_small">'.&searchhelp().'</span>'.'</td>'.
               '<td>'.
               '<span class="LC_nobreak">'.('&nbsp;'x3).$adv_search_link.'</span>'.'<br />'.
               '<span class="LC_nobreak">'.('&nbsp;'x1).$userelatedwords.'</span>'.'<br />'.
               '<span class="LC_nobreak">'.('&nbsp;'x1).$onlysearchdomain.'</span>'.'<br />'.
               '<span class="LC_nobreak">'.('&nbsp;'x1).$inclext.'</span>'.'<br />'.
                '</td>'.
               '</tr>'.
               '</table>'.$/;
       #
       $scrout .= '<p>'
                 .&viewoptions()
                 .'</p>'
                 .'<p>'
                 .'<input type="submit" name="basicsubmit" '
                 .'value="'.&mt('Search').'" />'
                 .' '
                 .$closebutton
                 .'</p>';
       #
       $scrout .= '</div>'.'</form>';
       return $scrout;
   } 
   
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
   
Line 454  ENDDOCUMENT Line 853  ENDDOCUMENT
   
 =item &advanced_search_form()   =item &advanced_search_form() 
   
 Returns a scalar which holds html for the advanced search form.  Prints the advanced search form.
   
 =cut  =cut
   
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
   
 sub print_advanced_search_form{  sub print_advanced_search_form{
     my ($r,$closebutton) = @_;      my ($r,$closebutton,$hidden_fields) = @_;
     my $advanced_buttons = <<"END";      my $bread_crumb = 
           &Apache::lonhtmlcommon::breadcrumbs('Searching','Search_Advanced',
       $env{'form.catalogmode'} ne 'import');
       my %lt=&Apache::lonlocal::texthash('srch' => 'Search',
          'reset' => 'Reset',
          'help' => 'Help');
       my $advanced_buttons=<<"END";
 <p>  <p>
 <input type="submit" name="advancedsubmit" value='SEARCH' />  <input type="submit" name="advancedsubmit" value='$lt{"srch"}' />
 <input type="reset" name="reset" value='RESET' />  <input type="reset" name="reset" value='$lt{"reset"}' />
 $closebutton  $closebutton
 <input type="button" value="HELP" onClick="openhelp()" />  
 </p>  </p>
 END  END
     if (!defined($ENV{'form.viewselect'})) {      my $srchtype = 'Catalog';
         $ENV{'form.viewselect'} ="Detailed Citation View";      my $jscript;
     }      if ($env{'form.area'} eq 'portfolio') {
     my $scrout=<<"ENDHEADER";          $srchtype = 'Portfolio';
 <html>          $jscript = '<script type="text/javascript">
 <head>  // <![CDATA[
 <title>The LearningOnline Network with CAPA</title>  function additional_metadata() {
 <script type="text/javascript">      if (document.advsearch.newfield.checked) {
     function openhelp(val) {          document.advsearch.phase.value = "disp_adv";
  openhelpwin=open('/adm/help/searchcat.html','helpscreen',          document.advsearch.numaddedfields.value = parseInt(document.advsearch.numaddedfields.value) +1;
      'scrollbars=1,width=600,height=300');          document.advsearch.submit();
  openhelpwin.focus();      }
   }
   // ]]>
   </script>';
       }
       my $scrout= &Apache::loncommon::start_page("Advanced $srchtype Search",
                                                  $jscript);
       $scrout .= $bread_crumb;
   
       $scrout .= '<form method="post" action="/adm/searchcat" name="advsearch">'
                 .$hidden_fields 
                 .'<input type="hidden" name="phase" value="adv_search" />';
   
       $scrout .= '<fieldset>'."\n"
                 .'<legend>'.&mt('Display Options').'</legend>'."\n"
                 .&viewoptions()
                 .'</fieldset>';
   
       $scrout .= $advanced_buttons;
   
       $scrout .= &Apache::lonhtmlcommon::start_pick_box();
   
       my %fields=&Apache::lonmeta::fieldnames();
   
       # Standard Metadata
       $scrout .= &Apache::lonhtmlcommon::row_headline()
                 .'<h3>'.&mt("Standard $srchtype Metadata").'</h3>'
                 .&searchhelp()
                 .&Apache::lonhtmlcommon::row_closure();
       my %related_word_search = 
           ('title'    => 1,
            'author'   => 0,
            'owner'    => 0,
            'authorspace'  => 0,
            'modifyinguser'=> 0,
            'keywords' => 1,
            'notes'    => 1,
            'abstract' => 1,
            'standards'=> 1,
            'mime'     => 1,
            'subject'  => 1,
            );
       #
       foreach my $field ('title','author','subject','owner','authorspace',
                          'modifyinguser','keywords','notes','abstract',
                          'standards','mime') {
           $scrout .= &Apache::lonhtmlcommon::row_title(&titlefield($fields{$field}))
                     .&Apache::lonmeta::prettyinput($field,
                                             $env{'form.'.$field},
                                             $field,
                                             'advsearch',
                                             $related_word_search{$field},
                                             '',
                                             $env{'form.'.$field.'_related'},
                                             50);
           if ($related_word_search{$field}) {
               $scrout .= &mt('related words');
           } else {
               $scrout .= '';
           }
           $scrout .= &Apache::lonhtmlcommon::row_closure();
     }      }
 </script>      foreach my $field ('lowestgradelevel','highestgradelevel') {
 </head>          $scrout .= &Apache::lonhtmlcommon::row_title(&titlefield($fields{$field}))
 <body bgcolor="#FFFFFF">                    .&Apache::lonmeta::prettyinput($field,
 <img align='right' src='/adm/lonIcons/lonlogos.gif' />                                            $env{'form.'.$field},
 <h1>Advanced Catalog Search</h1>                                            $field,
 <hr />                                            'advsearch',
 Enter terms or phrases separated by search operators                                             0)
 such as AND, OR, or NOT.<br />                    .&Apache::lonhtmlcommon::row_closure();
 <form method="post" action="/adm/searchcat">      }
 $advanced_buttons  
 $hidden_fields      $scrout .= &Apache::lonhtmlcommon::row_title(&titlefield(&mt('MIME Type Category')))
 <input type="hidden" name="phase" value="adv_search" />                .&Apache::loncommon::filecategoryselect('category',
 <table>                     $env{'form.category'})
 <tr><td><font color="#800000" face="helvetica"><b>VIEW:</b></font></td>                .&Apache::lonhtmlcommon::row_closure();
 <td>  
 ENDHEADER      $scrout .= &Apache::lonhtmlcommon::row_title(&titlefield(&mt('Domains')))
     $scrout.=&selectbox(undef,'viewselect',                .&Apache::loncommon::domain_select('domains',
  $ENV{'form.viewselect'},                     $env{'form.domains'},1)
  undef,undef,undef,                .&Apache::lonhtmlcommon::row_closure();
  sort(keys(%Views)));  
     $scrout.='&nbsp;';      # Misc metadata
     $scrout.=&selectbox(undef,'show',      if ($env{'form.area'} ne 'portfolio') {
  $ENV{'form.show'},          $scrout .= &Apache::lonhtmlcommon::row_title(&titlefield(&mt('Copyright/Distribution')))
  undef,undef,undef,                    .&Apache::lonmeta::selectbox('copyright',
  (10,20,50,100));                                               $env{'form.copyright'},
     $scrout.='&nbsp;'.                                  \&Apache::loncommon::copyrightdescription,
         '<font color="#800000" face="helvetica">Per Page</font>';                                         ( undef,
     $scrout.="</td><td>Related<br />Words</td></tr>\n";                                          &Apache::loncommon::copyrightids)
     $scrout.=&searchphrasefield_with_related('title',   'title'   ,                                  )
                                              $ENV{'form.title'});                    .&Apache::lonhtmlcommon::row_closure();
     $scrout.=&searchphrasefield('author',  'author'  ,$ENV{'form.author'});      }
     $scrout.=&searchphrasefield_with_related('subject', 'subject' ,  
                                              $ENV{'form.subject'});      $scrout .= &Apache::lonhtmlcommon::row_title(&titlefield(&mt('Language')))
     $scrout.=&searchphrasefield_with_related('keywords','keywords',                .&Apache::lonmeta::selectbox('language',
                                              $ENV{'form.keywords'});                                      $env{'form.language'},
     $scrout.=&searchphrasefield('URL',     'url'     ,$ENV{'form.url'});                                      \&Apache::loncommon::languagedescription,
     $scrout.=&searchphrasefield_with_related('notes',   'notes'   ,                                      ('any',&Apache::loncommon::languageids)
                                              $ENV{'form.notes'});                                      )
     $scrout.=&searchphrasefield_with_related('abstract','abstract',                .&Apache::lonhtmlcommon::row_closure();
                                              $ENV{'form.abstract'});      
     # Hack - an empty table row.      # Portfolio Metadata
     $scrout.="<tr><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>\n";      if ($env{'form.area'} eq 'portfolio') {
     $scrout.=&searchphrasefield('file<br />extension','mime',          # Added fields
                         $ENV{'form.mime'});          my $curnumadd = $env{'form.numaddedfields'};
     $scrout.="<tr><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>\n";          if ($curnumadd eq '') {
     $scrout.=&searchphrasefield('publisher<br />owner','owner',              $curnumadd = 1;
  $ENV{'form.owner'});          }
     $scrout.="</table>\n";          $scrout .= &Apache::lonhtmlcommon::row_headline()
     $ENV{'form.category'}='any' unless length($ENV{'form.category'});                    .'<h3>'.&mt('Custom Metadata fields').'</h3>'
     $scrout.=&selectbox('File Category','category',                    .&Apache::lonhtmlcommon::row_closure()
  $ENV{'form.category'},                    .&Apache::lonhtmlcommon::row_title('')
  'any','Any category',                    .&mt('Field Name').' | '.&mt('Field Value(s)')
  undef,                    .&Apache::lonhtmlcommon::row_closure();
  (&Apache::loncommon::filecategories()));  
     $ENV{'form.language'}='any' unless length($ENV{'form.language'});          for (my $j=0; $j<$curnumadd; $j++) {
     #----------------------------------------------------------------              my $num = $j+1;
     # Allow restriction to multiple domains.              $scrout .= &Apache::lonhtmlcommon::row_title(&mt('Custom metadata [_1]',$num))
     #   I make the crazy assumption that there will never be a domain 'any'.                        .'<input type="text"'
     #                        .' name="addedfield_'.$j.'" size="10"'
     $ENV{'form.domains'} = 'any' if (! exists($ENV{'form.domains'}));                        .' value="'.$env{'form.addedfield_'.$j}.'" />'
     my @allowed_domains = (ref($ENV{'form.domains'}) ? @{$ENV{'form.domains'}}                         .' '
                            :  ($ENV{'form.domains'}) );                        .'<input type="text" '
     my %domain_hash = ();                        .'name="addedvalues_'.$j.'" size="15"'
     foreach (@allowed_domains) {                        .' value="'.$env{'form.addedvalues_'.$j}.'" />'
         $domain_hash{$_}++;                        .&Apache::lonhtmlcommon::row_closure();
           }
           $scrout .= &Apache::lonhtmlcommon::row_title('')
                     .'<label>'
                     .'<input type="checkbox" name="newfield"'
                     .' value="1" onclick="javascript:additional_metadata()" />'
                     .&mt('Another custom field/value pair?').'</label>'
                     .'<input type="hidden" name="numaddedfields"'
                     .' value="'.$curnumadd.'" />'
                     .&Apache::lonhtmlcommon::row_closure();
   } else {
           #
           # Dynamic metadata
           $scrout .= &Apache::lonhtmlcommon::row_headline()
                     .'<h3>'.&mt('Problem Statistics').'</h3>'
                     .&Apache::lonhtmlcommon::row_closure();
           $scrout .= &Apache::lonhtmlcommon::row_title('')
                     .&mt('Minimum').' | '.&mt('Maximum')
                     .&Apache::lonhtmlcommon::row_closure();
           foreach my $statistic 
               ({ name=>'count',
                  description=>'Network-wide number of accesses (hits)',},
                { name=>'stdno',
                  description=>
                  'Statistics calculated for number of students',},
                { name => 'avetries',
                  description=>'Average number of tries till solved',},
                { name => 'difficulty',
                  description=>'Degree of difficulty',},
                { name => 'disc',
                  description=>'Degree of discrimination'}) {
                 $scrout .= &Apache::lonhtmlcommon::row_title(&titlefield(&mt($statistic->{'description'})))
                           .'<input type="text" name="'.$statistic->{'name'}
                           .'_min" value="" size="6" />'
                           .' '
                           .'<input type="text" name="'.$statistic->{'name'}
                           .'_max" value="" size="6" />'
                           .&Apache::lonhtmlcommon::row_closure();
           }
   
           $scrout .= &Apache::lonhtmlcommon::row_headline()
                     .'<h3>'.&mt('Evaluation Data').'</h3>'
                     .&Apache::lonhtmlcommon::row_closure();
           $scrout .= &Apache::lonhtmlcommon::row_title('')
                     .&mt('Minimum').' | '.&mt('Maximum')
                     .&Apache::lonhtmlcommon::row_closure();
           foreach my $evaluation
               ( { name => 'clear',
                   description => 'Material presented in clear way'},
                 { name =>'depth',
                   description => 'Material covered with sufficient depth'},
                 { name => 'helpful',
                   description => 'Material is helpful'},
                 { name => 'correct',
                   description => 'Material appears to be correct'},
                 { name => 'technical',
                   description => 'Resource is technically correct'}){
               $scrout .= &Apache::lonhtmlcommon::row_title(&titlefield(&mt($evaluation->{'description'})))
                         .'<input type="text" name="'
                         .$evaluation->{'name'}.'_min" value="" size="6" />'
                         .' '
                         .'<input type="text" name="'
                         .$evaluation->{'name'}.'_max" value="" size="6" />'
                         .&Apache::lonhtmlcommon::row_closure();
           }
     }      }
     my @domains =&Apache::loncommon::get_domains();      #
     # adjust the size of the select box      # Creation/Modification date limits
     my $size = 4;      $scrout .= &Apache::lonhtmlcommon::row_headline()
     my $size = (scalar @domains < ($size - 1) ? scalar @domains + 1 : $size);                .'<h3>'.&mt('Creation and Modification dates').'</h3>'
     $scrout.="\n".'<font color="#800000" face="helvetica"><b>'.                .&Apache::lonhtmlcommon::row_closure();
         'DOMAINS</b></font><br />'.      $scrout .= &Apache::lonhtmlcommon::row_title('')
             '<select name="domains" size="'.$size.'" multiple>'."\n".                .&mt('Month[_1]Day[_2]Year','&nbsp;'x14,'&nbsp;'x6)
                 '<option name="any" value="any" '.                .&Apache::lonhtmlcommon::row_closure();
                     ($domain_hash{'any'}? 'selected ' :'').  
                         '>all domains</option>'."\n";      my $cafter = 
     foreach my $dom (sort @domains) {          &Apache::lonhtmlcommon::date_setter('advsearch',         # formname
         $scrout.="<option name=\"$dom\" ".                                              'creationdate1', # fieldname
             ($domain_hash{$dom} ? 'selected ' :'').">$dom</option>\n";                                              0,           # current value
     }                                              '',          # special 
     $scrout.="</select>\n";                                              1,           # includeempty
     #----------------------------------------------------------------                                              '',          # state
     $scrout.=&selectbox('Limit by language','language',                                              1,           # no_hh_mm_ss
  $ENV{'form.language'},'any','Any Language',                                              );
  \&{Apache::loncommon::languagedescription},      my $cbefore = 
  (&Apache::loncommon::languageids),          &Apache::lonhtmlcommon::date_setter('advsearch',         # formname
  );                                              'creationdate2', # fieldname
 # ------------------------------------------------ Compute date selection boxes                                              0,           # current value
     $scrout.=<<CREATIONDATESTART;                                              '',          # special 
 <p>                                              1,           # includeempty
 <font color="#800000" face="helvetica"><b>LIMIT BY CREATION DATE RANGE:</b>                                              '',          # state
 </font>                                              1,           # no_hh_mm_ss
 <br />                                              );
 between:      $scrout .= &Apache::lonhtmlcommon::row_title(&mt('Created between'))
 CREATIONDATESTART                .$cafter
     $scrout.=&dateboxes('creationdatestart',1,1,1976,                .&Apache::lonhtmlcommon::row_closure(1)
  $ENV{'form.creationdatestart_month'},                .&Apache::lonhtmlcommon::row_title(&mt('and'))
  $ENV{'form.creationdatestart_day'},                .$cbefore
  $ENV{'form.creationdatestart_year'},                .&Apache::lonhtmlcommon::row_closure();
  );  
     $scrout.="and:\n";      my $lafter = 
     $scrout.=&dateboxes('creationdateend',12,31,2051,          &Apache::lonhtmlcommon::date_setter('advsearch',
  $ENV{'form.creationdateend_month'},                                              'revisiondate1', 
  $ENV{'form.creationdateend_day'},                                              0,           # current value
  $ENV{'form.creationdateend_year'},                                              '',          # special 
  );                                              1,           # includeempty
     $scrout.="</p>";                                              '',          # state
     $scrout.=<<LASTREVISIONDATESTART;                                              1,           # no_hh_mm_ss
 <p>                                              );
 <font color="#800000" face="helvetica"><b>LIMIT BY LAST REVISION DATE RANGE:      my $lbefore = 
 </b></font>          &Apache::lonhtmlcommon::date_setter('advsearch',
 <br />between:                                              'revisiondate2',
 LASTREVISIONDATESTART                                              0,           # current value
     $scrout.=&dateboxes('lastrevisiondatestart',1,1,1976,                                              '',          # special 
  $ENV{'form.lastrevisiondatestart_month'},                                              1,           # includeempty
  $ENV{'form.lastrevisiondatestart_day'},                                              '',          # state
  $ENV{'form.lastrevisiondatestart_year'},                                              1,           # no_hh_mm_ss
  );                                              );
     $scrout.=<<LASTREVISIONDATEEND;      $scrout .= &Apache::lonhtmlcommon::row_title(&mt('Last modified between'))
 and:                .$lafter
 LASTREVISIONDATEEND                .&Apache::lonhtmlcommon::row_closure(1)
     $scrout.=&dateboxes('lastrevisiondateend',12,31,2051,                .&Apache::lonhtmlcommon::row_title(&mt('and'))
  $ENV{'form.lastrevisiondateend_month'},                .$lbefore
  $ENV{'form.lastrevisiondateend_day'},                .&Apache::lonhtmlcommon::row_closure(1); # Last row of total pick_box
  $ENV{'form.lastrevisiondateend_year'},  
  );      $scrout .= &Apache::lonhtmlcommon::end_pick_box();
     $scrout.='</p>';  
     $ENV{'form.copyright'}='any' unless length($ENV{'form.copyright'});      $scrout .= $advanced_buttons
     $scrout.=&selectbox('Limit by copyright/distribution','copyright',                .'</form>';
  $ENV{'form.copyright'},  
  'any','Any copyright/distribution',      $scrout .= &Apache::loncommon::end_page();
  \&{Apache::loncommon::copyrightdescription},  
  (&Apache::loncommon::copyrightids),  
  );  
 # ------------------------------------------- Compute customized metadata field  
 #    $scrout.=<<CUSTOMMETADATA;  
 #<p>  
 #<font color="#800000" face="helvetica"><b>LIMIT BY SPECIAL METADATA FIELDS:</b>  
 #</font>  
 #For resource-specific metadata, enter in an expression in the form of   
 #<i>key</i>=<i>value</i> separated by operators such as AND, OR or NOT.<br />  
 #<b>Example:</b> grandmother=75 OR grandfather=85  
 #<br />  
 #CUSTOMMETADATA  
 #    $scrout.=&simpletextfield('custommetadata',$ENV{'form.custommetadata'});  
 #    $scrout.=<<CUSTOMSHOW;  
 #<p>  
 #<font color="#800000" face="helvetica"><b>SHOW SPECIAL METADATA FIELDS:</b>  
 #</font>  
 #Enter in a space-separated list of special metadata fields to show  
 #in a fielded listing for each record result.  
 #<br />  
 #CUSTOMSHOW  
 #    $scrout.=&simpletextfield('customshow',$ENV{'form.customshow'});  
     $scrout.=<<ENDDOCUMENT;  
 $advanced_buttons  
 </form>  
 </body>  
 </html>  
 ENDDOCUMENT  
     $r->print($scrout);      $r->print($scrout);
     return;      return;
 }  }
Line 653  ENDDOCUMENT Line 1151  ENDDOCUMENT
   
 =pod   =pod 
   
 =item &get_persistent_form_data  =item &titlefield()
   
   Inputs: title text
   
   Outputs: titletext with font wrapper
   
   =cut
   
   ######################################################################
   ######################################################################
   sub titlefield {
       my $title=shift;
       return $title;
   }
   
   ######################################################################
   ######################################################################
   
   =pod 
   
   =item viewoptiontext()
   
   Inputs: codename for view option
   
   Outputs: displayed text
   
   =cut
   
   ######################################################################
   ######################################################################
   sub viewoptiontext {
       my $code=shift;
       my %desc=&Apache::lonlocal::texthash
           ('detailed' => "Detailed Citation View",
            'xml' => 'XML/SGML',
            'compact' => 'Compact View',
            'fielded' => 'Fielded Format',
            'summary' => 'Summary View',
            'summarypreview' => 'Summary Preview',
            'detailedpreview' => 'Detailed Citation Preview');
       return $desc{$code};
   }
   
   ######################################################################
   ######################################################################
   
   =pod 
   
   =item viewoptions()
   
   Inputs: none
   
   Outputs: text for box with view options
   
   =cut
   
   ######################################################################
   ######################################################################
   sub viewoptions {
       my $scrout;
       if (! defined($env{'form.viewselect'})) { 
           $env{'form.viewselect'}='detailed'; 
       }
       $scrout .= '<span class="LC_nobreak">'
                 .&mt('Type:').' '
                 .&Apache::lonmeta::selectbox('viewselect',
                      $env{'form.viewselect'},
                      \&viewoptiontext,
                      sort(keys(%Views)))
                 .'</span>';
       my $countselect = &Apache::lonmeta::selectbox('show',
                                                     $env{'form.show'},
                                                     undef,
                                                     (10,20,50,100,1000,10000));
       $scrout .= ' <span class="LC_nobreak">'
                 .&mt('Records per Page:').' '.$countselect
                 .'</span>'.$/;
       return $scrout;
   }
   
   ######################################################################
   ######################################################################
   
   =pod 
   
   =item searchhelp()
   
   Inputs: none
   
   Outputs: return little blurb on how to enter searches
   
   =cut
   
   ######################################################################
   ######################################################################
   sub searchhelp {
       return &mt('Enter words and quoted phrases');
   }
   
   ######################################################################
   ######################################################################
   
   =pod 
   
   =item &get_persistent_form_data()
   
 Inputs: filename of database  Inputs: filename of database
   
Line 661  Outputs: returns undef on database error Line 1263  Outputs: returns undef on database error
   
 This function is the reverse of &make_persistent() for form data.  This function is the reverse of &make_persistent() for form data.
 Retrieve persistent data from %persistent_db.  Retrieved items will have their  Retrieve persistent data from %persistent_db.  Retrieved items will have their
 values unescaped.  If a form value already exists in $ENV, it will not be  values unescaped.  If a form value already exists in $env, it will not be
 overwritten.  Form values that are array references may have values appended  overwritten.  Form values that are array references may have values appended
 to them.  to them.
   
Line 676  sub get_persistent_form_data { Line 1278  sub get_persistent_form_data {
                            &GDBM_READER(),0640));                             &GDBM_READER(),0640));
     #      #
     # These make sure we do not get array references printed out as 'values'.      # These make sure we do not get array references printed out as 'values'.
     my %arrays_allowed = ('form.category'=>1,'form.domains'=>1);      my %arrays_allowed = ('form.domains'=>1);
     #      #
     # Loop through the keys, looking for 'form.'      # Loop through the keys, looking for 'form.'
     foreach my $name (keys(%persistent_db)) {      foreach my $name (keys(%persistent_db)) {
         next if ($name !~ /^form./);          next if ($name !~ /^form./);
         next if (exists($ENV{$name}));          # Kludgification begins!
           if ($name eq 'form.domains' && 
               $env{'form.searchmode'} eq 'basic' &&
               $env{'form.phase'} ne 'disp_basic') {
               next;
           }
           # End kludge (hopefully)
           next if (exists($env{$name}));
         my @values = map {           my @values = map { 
             &Apache::lonnet::unescape($_);              &unescape($_);
         } split(',',$persistent_db{$name});          } split(',',$persistent_db{$name});
         next if (@values <1);          next if (@values <1);
         if ($arrays_allowed{$name}) {          if ($arrays_allowed{$name}) {
             $ENV{$name} = [@values];              $env{$name} = [@values];
         } else {          } else {
             $ENV{$name} = $values[0] if ($values[0]);              $env{$name} = $values[0] if ($values[0]);
         }          }
     }      }
     untie (%persistent_db);      untie (%persistent_db);
     return 1;      return 1;
 }  }
   
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
   
 =pod   =pod 
   
 =item &get_persistent_data  =item &get_persistent_data()
   
 Inputs: filename of database, ref to array of values to recover.  Inputs: filename of database, ref to array of values to recover.
   
Line 728  sub get_persistent_data { Line 1338  sub get_persistent_data {
             next;              next;
         }          }
         my @values = map {           my @values = map { 
             &Apache::lonnet::unescape($_);              &unescape($_);
         } split(',',$persistent_db{$name});          } split(',',$persistent_db{$name});
         if (@values <= 1) {          if (@values <= 1) {
             push @Values,$values[0];              push @Values,$values[0];
Line 751  Inputs: Hash of values to save, filename Line 1361  Inputs: Hash of values to save, filename
   
 Store variables away to the %persistent_db.  Store variables away to the %persistent_db.
 Values will be escaped.  Values that are array pointers will have their  Values will be escaped.  Values that are array pointers will have their
 elements escaped and concatenated in a comma seperated string.    elements escaped and concatenated in a comma separated string.  
   
 =cut  =cut
   
Line 765  sub make_persistent { Line 1375  sub make_persistent {
     foreach my $name (keys(%save)) {      foreach my $name (keys(%save)) {
         my @values = (ref($save{$name}) ? @{$save{$name}} : ($save{$name}));          my @values = (ref($save{$name}) ? @{$save{$name}} : ($save{$name}));
         # We handle array references, but not recursively.          # We handle array references, but not recursively.
         my $store = join(',', map { &Apache::lonnet::escape($_); } @values );          my $store = join(',', map { &escape($_); } @values );
         $persistent_db{$name} = $store;          $persistent_db{$name} = $store;
     }      }
     untie(%persistent_db);      untie(%persistent_db);
Line 783  Inputs: filename of persistent database. Line 1393  Inputs: filename of persistent database.
   
 Store most form variables away to the %persistent_db.  Store most form variables away to the %persistent_db.
 Values will be escaped.  Values that are array pointers will have their  Values will be escaped.  Values that are array pointers will have their
 elements escaped and concatenated in a comma seperated string.    elements escaped and concatenated in a comma separated string.  
   
 =cut  =cut
   
Line 793  sub make_form_data_persistent { Line 1403  sub make_form_data_persistent {
     my $r = shift;      my $r = shift;
     my $filename = shift;      my $filename = shift;
     my %save;      my %save;
     foreach (keys(%ENV)) {      foreach (keys(%env)) {
         next if (!/^form/ || /submit/);          next if (!/^form/ || /submit/);
         $save{$_} = $ENV{$_};          $save{$_} = $env{$_};
     }      }
     return &make_persistent(\%save,$filename);      return &make_persistent(\%save,$filename);
 }  }
   
 ######################################################################  ######################################################################
 #                HTML form building functions                        #    
 ######################################################################  
   
 =pod   
   
 =item HTML form building functions  
   
 =over 4  
   
 =cut  
   
 ###############################################  
 ###############################################  
   
 =pod  
   
 =item &simpletextfield()   
   
 Inputs: $name,$value,$size  
   
 Returns a text input field with the given name, value, and size.    
 If size is not specified, a value of 20 is used.  
   
 =cut  
   
 ###############################################  
 ###############################################  
   
 sub simpletextfield {  
     my ($name,$value,$size)=@_;  
     $size = 20 if (! defined($size));  
     return '<input type="text" name="'.$name.  
         '" size="'.$size.'" value="'.$value.'" />';  
 }  
   
 ###############################################  
 ###############################################  
   
 =pod  
   
 =item &simplecheckbox()  
   
 Inputs: $name,$value  
   
 Returns a simple check box with the given $name.  
 If $value eq 'on' the box is checked.  
   
 =cut  
   
 ###############################################  
 ###############################################  
   
 sub simplecheckbox {  
     my ($name,$value)=@_;  
     my $checked='';  
     $checked="checked" if $value eq 'on';  
     return '<input type="checkbox" name="'.$name.'" '. $checked . ' />';  
 }  
   
 ###############################################  
 ###############################################  
   
 =pod  
   
 =item &fieldtitle()  
   
 Input: $title  
   
 Returns a scalar with html which will display $title as a search  
 field heading.  
   
 =cut  
   
 ###############################################  
 ###############################################  
   
 sub fieldtitle {  
     my $title = uc(shift());  
     return '<font color="#800000" face="helvetica"><b>'.$title.  
         ':&nbsp;</b></font>';  
 }  
   
 ###############################################  
 ###############################################  
   
 =pod  
   
 =item &searchphrasefield()  
   
 Inputs: $title,$name,$value  
   
 Returns html for a title line and an input field for entering search terms.  
 The entry field (which is where the $name and $value are used) is a 50 column   
 simpletextfield.  The html returned is for a row in a three column table.  
   
 =cut  
   
 ###############################################  
 ###############################################  
       
 sub searchphrasefield {  
     my ($title,$name,$value)=@_;  
     return '<tr><td>'.&fieldtitle($title).'</td><td>'.  
         &simpletextfield($name,$value,50)."</td><td>&nbsp;</td></tr>\n";  
 }  
   
 ###############################################  
 ###############################################  
   
 =pod  
   
 =item &searchphrasefield_with_related()  
   
 Inputs: $title,$name,$value  
   
 Returns html for a title line and an input field for entering search terms  
 and a check box for 'related words'.  The entry field (which is where the   
 $name and $value are used) is a 50 column simpletextfield.  The name of  
 the related words checkbox is "$name_related".  
   
 =cut  
   
 ###############################################  
 ###############################################  
       
 sub searchphrasefield_with_related {  
     my ($title,$name,$value)=@_;  
     return '<tr><td>'.&fieldtitle($title).'</td><td>'.  
         &simpletextfield($name,$value,50).'</td><td align="center">&nbsp;'.  
             &simplecheckbox($name.'_related',$ENV{'form.'.$name.'_related'}).  
                 "&nbsp;</td></tr>\n";  
 }  
   
 ###############################################  
 ###############################################  
   
 =pod  
   
 =item &dateboxes()  
   
 Returns html selection form elements for the specification of   
 the day, month, and year.  
   
 =cut  
   
 ###############################################  
 ###############################################  
   
 sub dateboxes {  
     my ($name,$defaultmonth,$defaultday,$defaultyear,  
  $currentmonth,$currentday,$currentyear)=@_;  
     ($defaultmonth,$defaultday,$defaultyear)=('','','');  
     #  
     # Day  
     my $day=<<END;  
 <select name="${name}_day">  
 <option value='$defaultday'> </option>  
 END  
     for (my $i = 1; $i<=31; $i++) {  
  $day.="<option value=\"$i\">$i</option>\n";  
     }  
     $day.="</select>\n";  
     $day=~s/(\"$currentday\")/$1 SELECTED/ if length($currentday);  
     #  
     # Month  
     my $month=<<END;  
 <select name="${name}_month">  
 <option value='$defaultmonth'> </option>  
 END  
     my $i = 1;  
     foreach (qw/January February March April May June   
      July August September October November December /){  
  $month .="<option value=\"$i\">$_</option>\n";  
  $i++;  
     }  
     $month.="</select>\n";  
     $month=~s/(\"$currentmonth\")/$1 SELECTED/ if length($currentmonth);  
     #  
     # Year (obviously)  
     my $year=<<END;  
 <select name="${name}_year">  
 <option value='$defaultyear'> </option>  
 END  
     my $maxyear = 2051;   
     for (my $i = 1976; $i<=$maxyear; $i++) {  
  $year.="<option value=\"$i\">$i</option>\n";  
     }  
     $year.="</select>\n";  
     $year=~s/(\"$currentyear\")/$1 SELECTED/ if length($currentyear);  
     return "$month$day$year";  
 }  
   
 ###############################################  
 ###############################################  
   
 =pod  
   
 =item &selectbox()  
   
 Returns a scalar containing an html <select> form.    
   
 Inputs:   
   
 =over 4  
   
 =item $title   
   
 Printed above the select box, in uppercase.  If undefined, only a select  
 box will be returned, with no additional html.  
   
 =item $name   
   
 The name element of the <select> tag.  
   
 =item $default   
   
 The default value of the form.  Can be $anyvalue, or in @idlist.  
   
 =item $anyvalue   
   
 The <option value="..."> used to indicate a default of   
 none of the values.  Can be undef.  
   
 =item $anytag   
   
 The text associate with $anyvalue above.  
   
 =item $functionref   
   
 Each element in @idlist will be passed as a parameter   
 to the function referenced here.  The return value of the function should  
 be a scalar description of the items.  If this value is undefined the   
 description of each item in @idlist will be the item name.  
   
 =item @idlist   
   
 The items to be selected from.  One of these or $anyvalue will be the   
 value returned by the form element, $ENV{form.$name}.  
   
 =back  
   
 =cut  
   
 ###############################################  
   
 sub selectbox {  
     my ($title,$name,$default,$anyvalue,$anytag,$functionref,@idlist)=@_;  
     if (! defined($functionref)) { $functionref = sub { $_[0]}; }  
     my $selout='';  
     if (defined($title)) {  
         my $uctitle=uc($title);  
         $selout="\n".'<p><font color="#800000" face="helvetica">'.  
             '<b>'.$uctitle.': </b></font>';  
     }  
     $selout .= '<select name="'.$name.'">';  
     unshift @idlist,$anyvalue if (defined($anyvalue));  
     foreach (@idlist) {  
         $selout.='<option value="'.$_.'"';  
         if ($_ eq $default and !/^any$/) {  
     $selout.=' selected >'.&{$functionref}($_).'</option>';  
  }  
  elsif ($_ eq $default and /^$anyvalue$/) {  
     $selout.=' selected >'.$anytag.'</option>';  
  }  
         else {$selout.='>'.&{$functionref}($_).'</option>';}  
     }  
     return $selout.'</select>'.(defined($title)?'</p>':' ');  
 }  
   
 ######################################################################  
 #                End of HTML form building functions                 #    
 ######################################################################  
   
 =pod  
   
 =back   
   
 =cut  
   
   
 ######################################################################  
 ######################################################################  ######################################################################
   
 =pod   =pod 
Line 1107  Parse advanced search form and return th Line 1436  Parse advanced search form and return th
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
 sub parse_advanced_search {  sub parse_advanced_search {
     my ($r,$closebutton)=@_;      my ($r,$closebutton,$hidden_fields)=@_;
       my @BasicFields = ('title','author','subject','keywords','url','version',
                          'notes','abstract','extension','owner','authorspace',
   #                       'custommetadata','customshow',
                          'modifyinguser','standards','mime');
       my @StatsFields = &statfields();
       my @EvalFields = &evalfields();
     my $fillflag=0;      my $fillflag=0;
     my $pretty_search_string = "<br />\n";      my $pretty_search_string = "";
     # Clean up fields for safety      # Clean up fields for safety
     for my $field ('title','author','subject','keywords','url','version',      for my $field (@BasicFields,
    'creationdatestart_month','creationdatestart_day',                     'creationdatestart_month','creationdatestart_day',
    'creationdatestart_year','creationdateend_month',     'creationdatestart_year','creationdateend_month',
    'creationdateend_day','creationdateend_year',     'creationdateend_day','creationdateend_year',
    'lastrevisiondatestart_month','lastrevisiondatestart_day',     'lastrevisiondatestart_month','lastrevisiondatestart_day',
    'lastrevisiondatestart_year','lastrevisiondateend_month',     'lastrevisiondatestart_year','lastrevisiondateend_month',
    'lastrevisiondateend_day','lastrevisiondateend_year',     'lastrevisiondateend_day','lastrevisiondateend_year') {
    'notes','abstract','mime','language','owner',   $env{'form.'.$field}=~s/[^\w\/\s\(\)\=\-\"\'.\*]//g;
    'custommetadata','customshow','category') {  
  $ENV{"form.$field"}=~s/[^\w\/\s\(\)\=\-\"\']//g;  
     }      }
     foreach ('mode','form','element') {      foreach ('mode','form','element') {
  # is this required?  Hmmm.   # is this required?  Hmmm.
  next unless (exists($ENV{"form.$_"}));   next if (! exists($env{'form.'.$_}));
  $ENV{"form.$_"}=&Apache::lonnet::unescape($ENV{"form.$_"});   $env{'form.'.$_}=&unescape($env{'form.'.$_});
  $ENV{"form.$_"}=~s/[^\w\/\s\(\)\=\-\"\']//g;   $env{'form.'.$_}=~s/[^\w\/\s\(\)\=\-\"\']//g;
     }      }
     # Preprocess the category form element.      # Preprocess the category form element.
     $ENV{'form.category'} = 'any' if (ref($ENV{'form.category'}));      $env{'form.category'} = 'any' if (! defined($env{'form.category'}) ||
     if ($ENV{'form.category'} ne 'any') {                                        ref($env{'form.category'}));
         my @extensions = &Apache::loncommon::filecategorytypes      #
             ($ENV{'form.category'});  
         $ENV{'form.mime'} = join ' OR ',@extensions;  
     }  
     # Check to see if enough information was filled in      # Check to see if enough information was filled in
     for my $field ('title','author','subject','keywords','url','version',      foreach my $field (@BasicFields) {
    'notes','abstract','mime','language','owner',   if (&filled($env{'form.'.$field})) {
    'custommetadata') {  
  if (&filled($ENV{"form.$field"})) {  
     $fillflag++;      $fillflag++;
  }   }
     }      }
     unless ($fillflag) {      foreach my $field (@StatsFields,@EvalFields) {
  &output_blank_field_error($r,$closebutton,'phase=disp_adv');          if (&filled($env{'form.'.$field.'_max'})) {
               $fillflag++;
           }
           if (&filled($env{'form.'.$field.'_min'})) {
               $fillflag++;
           }
       }
   
       for my $field ('lowestgradelevel','highestgradelevel') {
           if ( $env{'form.'.$field} =~ /^\d+$/ &&
                $env{'form.'.$field} > 0) {
               $fillflag++;
           }
       }
       if ($env{'form.area'} eq 'portfolio') {
           # Added metadata fields
           for (my $i=0; $i<$env{'form.numaddedfields'} ; $i++) {
               my $field = $env{'form.addedfield_'.$i};
               $field =~ s/^\s*(\S*)\s*$/$1/;
               $field =~ s/\W/_/g;
               if ($field ne '') {
                   $fillflag++;
               }
           }
       }
       if (! $fillflag) {
    &output_blank_field_error($r,$closebutton,
                                     'phase=disp_adv',$hidden_fields);
  return ;   return ;
     }      }
     # Turn the form input into a SQL-based query      # Turn the form input into a SQL-based query
Line 1152  sub parse_advanced_search { Line 1507  sub parse_advanced_search {
     my @queries;      my @queries;
     my $font = '<font color="#800000" face="helvetica">';      my $font = '<font color="#800000" face="helvetica">';
     # Evaluate logical expression AND/OR/NOT phrase fields.      # Evaluate logical expression AND/OR/NOT phrase fields.
     foreach my $field ('title','author','subject','notes','abstract','url',      foreach my $field (@BasicFields) {
        'keywords','version','owner','mime') {   next if (!defined($env{'form.'.$field}) || $env{'form.'.$field} eq '');
  if ($ENV{'form.'.$field}) {          my ($error,$SQLQuery) = 
             my $searchphrase = $ENV{'form.'.$field};              &process_phrase_input($env{'form.'.$field},
             $pretty_search_string .= $font."$field</font> contains <b>".                                    $env{'form.'.$field.'_related'},$field);
                 $searchphrase."</b>";          if (defined($error)) {
             if ($ENV{'form.'.$field.'_related'}) {              &output_unparsed_phrase_error($r,$closebutton,'phase=disp_adv',
                 my @New_Words;                                           $hidden_fields,$field);
                 ($searchphrase,@New_Words) = &related_version($searchphrase);              return;
                 if (@New_Words) {          } else {
                     $pretty_search_string .= " with related words: ".              $pretty_search_string .= 
                         "<b>@New_Words</b>.";                  $font.$field.'</font>: '.$env{'form.'.$field};
               if ($env{'form.'.$field.'_related'}) {
                   my @Words = 
                       &Apache::loncommon::get_related_words
                       ($env{'form.'.$field});
                   if (@Words) {
                       $pretty_search_string.= ' with related words: '.
                           join(', ',@Words[0..4]);
                 } else {                  } else {
                     $pretty_search_string .= " with no related words.";                      $pretty_search_string.= ' with related words.';
                 }                  }
             }              }
             $pretty_search_string .= "<br />\n";              $pretty_search_string .= '<br />';
     push @queries,&build_SQL_query($field,$searchphrase);              push (@queries,$SQLQuery);
         }          }
     }      }
     # I dislike the hack below.      #
     if ($ENV{'form.category'}) {      # Make the 'mime' from 'form.category' and 'form.extension'
         $ENV{'form.mime'}='';      #
       my $searchphrase;
       if (exists($env{'form.category'})    && 
           $env{'form.category'} !~ /^\s*$/ &&
           $env{'form.category'} ne 'any')     {
           my @extensions = &Apache::loncommon::filecategorytypes
                                                      ($env{'form.category'});
           if (scalar(@extensions) > 0) {
               $searchphrase = join(' OR ',@extensions);
           }
     }      }
       if (defined($searchphrase)) {
           my ($error,$SQLsearch) = &process_phrase_input($searchphrase,0,'mime');
           push @queries,$SQLsearch;
           $pretty_search_string .=$font.'mime</font> contains <b>'.
               $searchphrase.'</b><br />';
       }
       #
     # Evaluate option lists      # Evaluate option lists
     if ($ENV{'form.language'} and $ENV{'form.language'} ne 'any') {      if ($env{'form.lowestgradelevel'}        &&
  push @queries,"(language like \"$ENV{'form.language'}\")";          $env{'form.lowestgradelevel'} ne '0' &&
           $env{'form.lowestgradelevel'} =~ /^\d+$/) {
    push(@queries,
                '(lowestgradelevel>='.$env{'form.lowestgradelevel'}.')');
           $pretty_search_string.="lowestgradelevel>=".
               $env{'form.lowestgradelevel'}."<br />\n";
       }
       if ($env{'form.highestgradelevel'}        &&
           $env{'form.highestgradelevel'} ne '0' &&
           $env{'form.highestgradelevel'} =~ /^\d+$/) {
    push(@queries,
                '(highestgradelevel<='.$env{'form.highestgradelevel'}.')');
           $pretty_search_string.="highestgradelevel<=".
               $env{'form.highestgradelevel'}."<br />\n";
       }
       if ($env{'form.language'} and $env{'form.language'} ne 'any') {
    push @queries,"(language like \"$env{'form.language'}\")";
         $pretty_search_string.=$font."language</font>= ".          $pretty_search_string.=$font."language</font>= ".
             &Apache::loncommon::languagedescription($ENV{'form.language'}).              &Apache::loncommon::languagedescription($env{'form.language'}).
                 "<br />\n";                  "<br />\n";
     }      }
     if ($ENV{'form.copyright'} and $ENV{'form.copyright'} ne 'any') {      if ($env{'form.copyright'} and $env{'form.copyright'} ne 'any') {
  push @queries,"(copyright like \"$ENV{'form.copyright'}\")";   push @queries,"(copyright like \"$env{'form.copyright'}\")";
         $pretty_search_string.=$font."copyright</font> = ".          $pretty_search_string.=$font."copyright</font> = ".
             &Apache::loncommon::copyrightdescription($ENV{'form.copyright'}).              &Apache::loncommon::copyrightdescription($env{'form.copyright'}).
                 "<br \>\n";                  "<br />\n";
       }
       if ($env{'form.area'} eq 'portfolio') {
           #
           # Added metadata fields
           for (my $i=0; $i<$env{'form.numaddedfields'} ; $i++) {
               my $field = $env{'form.addedfield_'.$i};
               $field =~ s/^\s*(\S*)\s*$/$1/;
               $field =~ s/\W/_/g;
               $field =~ tr/A-Z/a-z/; 
               if ($field ne '') {
                   my $value = $env{'form.addedvalues_'.$i};
                   if ($value ne '') {
                       $value =~ s/'/''/g; #' stupid emacs
                       my ($error,$query) = 
                           &process_phrase_input($value,0,'pf.value');
                       if (!defined($error)) {
                           push(@queries,"pf.field = '$field' AND $query");
                           $pretty_search_string .=
                               $font.$field.'</font>: '.
                               $env{'form.addedvalues_'.$i}.'<br />';
                       }
                   } else {
                       push(@queries,"pf.field = '$field' AND pf.value IS NULL");
                   }
               }
           }
       } else {
           #
           # Statistics
           foreach my $field (@StatsFields,@EvalFields) {
               my ($min,$max);
               if (exists($env{'form.'.$field.'_min'}) && 
                   $env{'form.'.$field.'_min'} ne '') {
                   $min = $env{'form.'.$field.'_min'};
               }
               if (exists($env{'form.'.$field.'_max'}) &&
                   $env{'form.'.$field.'_max'} ne '') {
                   $max = $env{'form.'.$field.'_max'};
               }
               next if (! defined($max) && ! defined($min));
               if (defined($min) && defined($max)) {
                   ($min,$max) = sort {$a <=>$b} ($min,$max);
               }
               if (defined($min) && $min =~ /^(\d+\.\d+|\d+|\.\d+)$/) {
                   push(@queries,'('.$field.'>'.$min.')');
                   $pretty_search_string.=$font.$field.'</font>&gt;'.$min.'<br />';
               }
               if (defined($max) && $max =~ /^(\d+\.\d+|\d+|\.\d+)$/) {
                   push(@queries,'('.$field.'<'.$max.')');
                   $pretty_search_string.=$font.$field.'</font>&lt;'.$max.'<br />';
               }
           }
     }      }
     #      #
     # Evaluate date windows      # Evaluate date windows
     my $datequery=&build_date_queries(      my $cafter =
  $ENV{'form.creationdatestart_month'},          &Apache::lonhtmlcommon::get_date_from_form('creationdate1');
  $ENV{'form.creationdatestart_day'},      my $cbefore = 
  $ENV{'form.creationdatestart_year'},          &Apache::lonhtmlcommon::get_date_from_form('creationdate2');
  $ENV{'form.creationdateend_month'},      if ($cafter > $cbefore) {
  $ENV{'form.creationdateend_day'},          my $tmp = $cafter;
  $ENV{'form.creationdateend_year'},          $cafter = $cbefore;
  $ENV{'form.lastrevisiondatestart_month'},          $cbefore = $tmp;
  $ENV{'form.lastrevisiondatestart_day'},      }
  $ENV{'form.lastrevisiondatestart_year'},      my $mafter = 
  $ENV{'form.lastrevisiondateend_month'},          &Apache::lonhtmlcommon::get_date_from_form('revisiondate1');
  $ENV{'form.lastrevisiondateend_day'},      my $mbefore =
  $ENV{'form.lastrevisiondateend_year'},          &Apache::lonhtmlcommon::get_date_from_form('revisiondate2');
  );      if ($mafter > $mbefore) {
     # Test to see if date windows are legitimate          my $tmp = $mafter;
     if ($datequery=~/^Incorrect/) {          $mafter = $mbefore;
  &output_date_error($r,$datequery,$closebutton);          $mbefore = $tmp;
  return ;      }
     } elsif ($datequery) {      my ($datequery,$error,$prettydate)=&build_date_queries($cafter,$cbefore,
                                                              $mafter,$mbefore);
       if (defined($error)) {
           &output_date_error($r,$error,$closebutton,$hidden_fields);
       } elsif (defined($datequery)) {
         # Here is where you would set up pretty_search_string to output          # Here is where you would set up pretty_search_string to output
         # date query information.          # date query information.
           $pretty_search_string .= '<br />'.$prettydate.'<br />';
  push @queries,$datequery;   push @queries,$datequery;
     }      }
       #
     # Process form information for custom metadata querying      # Process form information for custom metadata querying
     my $customquery=undef;      my $customquery=undef;
 #    if ($ENV{'form.custommetadata'}) {      ##
 #        $pretty_search_string .=$font."Custom Metadata Search</font>: <b>".      ## The custom metadata search was removed q long time ago mostly 
 #            $ENV{'form.custommetadata'}."</b><br />\n";      ## because I was unable to figureout exactly how it worked and could
 # $customquery=&build_custommetadata_query('custommetadata',      ## not imagine people actually using it.  MH
 #      $ENV{'form.custommetadata'});      ##
 #    }      # if ($env{'form.custommetadata'}) {
       #    $pretty_search_string .=$font."Custom Metadata Search</font>: <b>".
       #    $env{'form.custommetadata'}."</b><br />\n";
       #    $customquery=&build_custommetadata_query('custommetadata',
       #                                             $env{'form.custommetadata'});
       # }
     my $customshow=undef;      my $customshow=undef;
 #    if ($ENV{'form.customshow'}) {      # if ($env{'form.customshow'}) {
 #        $pretty_search_string .=$font."Custom Metadata Display</font>: <b>".      # $pretty_search_string .=$font."Custom Metadata Display</font>: <b>".
 #            $ENV{'form.customshow'}."</b><br />\n";      #                         $env{'form.customshow'}."</b><br />\n";
 # $customshow=$ENV{'form.customshow'};      #    $customshow=$env{'form.customshow'};
 # $customshow=~s/[^\w\s]//g;      #    $customshow=~s/[^\w\s]//g;
 # my @fields=split(/\s+/,$customshow);      #    my @fields=split(/\s+/,$customshow);
 # $customshow=join(" ",@fields);      #    $customshow=join(" ",@fields);
 #    }      # }
     ## ---------------------------------------------------------------      ##
     ## Deal with restrictions to given domains      ## Deal with restrictions to given domains
     ##       ## 
       my ($libraries_to_query,$pretty_domains_string) = &parse_domain_restrictions();
       if ($pretty_domains_string) {
          $pretty_search_string .= $pretty_domains_string."<br />\n";
       }
       #
       if (@queries) {
           if ($env{'form.area'} eq 'portfolio') {
               $query ="SELECT pm.*,pa.keynum,pa.scope FROM portfolio_metadata pm, portfolio_access pa, portfolio_addedfields pf WHERE (pm.url = pa.url AND pf.url = pm.url AND (pa.start < UTC_TIMESTAMP() AND (pa.end IS NULL OR pa.end > UTC_TIMESTAMP())) AND (".join(') AND (',@queries).'))';
           } else {
       $query="SELECT * FROM metadata WHERE (".join(") AND (",@queries).')';
           }
       } elsif ($customquery) {
           $query = '';
       }
       #&Apache::lonnet::logthis('advanced query = '.$/.$query);
       return ($query,$customquery,$customshow,$libraries_to_query,
               $pretty_search_string);
   }
   
   sub parse_domain_restrictions {
     my $libraries_to_query = undef;      my $libraries_to_query = undef;
     # $ENV{'form.domains'} can be either a scalar or an array reference.      # $env{'form.domains'} can be either a scalar or an array reference.
     # We need an array.      # We need an array.
     my @allowed_domains = (ref($ENV{'form.domains'}) ? @{$ENV{'form.domains'}}       if (! exists($env{'form.domains'}) || $env{'form.domains'} eq '') {
                            :  ($ENV{'form.domains'}) );          return (undef,'',undef);
       }
       my @allowed_domains = &Apache::loncommon::get_env_multiple('form.domains');
       #
     my %domain_hash = ();      my %domain_hash = ();
     my $pretty_domains_string;      my $pretty_domains_string;
     foreach (@allowed_domains) {      foreach (@allowed_domains) {
         $domain_hash{$_}++;          $domain_hash{$_}++;
     }      }
     if ($domain_hash{'any'}) {      if ($domain_hash{'any'}) {
         $pretty_domains_string = "In all LON-CAPA domains.";          $pretty_domains_string = &mt("in all LON-CAPA domains.");
     } else {      } else {
         if (@allowed_domains > 1) {          if (@allowed_domains > 1) {
             $pretty_domains_string = "In LON-CAPA domains:";              $pretty_domains_string = &mt("in LON-CAPA domains:");
         } else {          } else {
             $pretty_domains_string = "In LON-CAPA domain ";              $pretty_domains_string = &mt("in LON-CAPA domain ");
         }          }
         foreach (sort @allowed_domains) {          foreach (sort @allowed_domains) {
             $pretty_domains_string .= "<b>".$_."</b> ";              $pretty_domains_string .= "<b>".$_."</b> ";
         }          }
         foreach (keys(%Apache::lonnet::libserv)) {   my %servers = &Apache::lonnet::get_servers(\@allowed_domains,
             if (exists($domain_hash{$Apache::lonnet::hostdom{$_}})) {     'library');
                 push @$libraries_to_query,$_;   $libraries_to_query = [keys(%servers)];
             }  
         }  
     }      }
     $pretty_search_string .= $pretty_domains_string."<br />\n";      return ($libraries_to_query,
     #              $pretty_domains_string);
     if (@queries) {  
  $query=join(" AND ",@queries);  
  $query="select * from metadata where $query";  
     } elsif ($customquery) {  
         $query = '';  
     }  
     return ($query,$customquery,$customshow,$libraries_to_query,  
             $pretty_search_string);  
 }  }
   
 ######################################################################  ######################################################################
Line 1288  Parse the basic search form and return a Line 1758  Parse the basic search form and return a
 ######################################################################  ######################################################################
 sub parse_basic_search {  sub parse_basic_search {
     my ($r,$closebutton)=@_;      my ($r,$closebutton)=@_;
       #
     # Clean up fields for safety      # Clean up fields for safety
     for my $field ('basicexp') {      for my $field ('basicexp') {
  $ENV{"form.$field"}=~s/[^\w\s\(\)\-]//g;   $env{"form.$field"}=~s/[^\w\s\'\"\!\(\)\-\*]//g;
     }      }
     foreach ('mode','form','element') {      foreach ('mode','form','element') {
  # is this required?  Hmmm.   # is this required?  Hmmm.
  next unless (exists($ENV{"form.$_"}));   next unless (exists($env{"form.$_"}));
  $ENV{"form.$_"}=&Apache::lonnet::unescape($ENV{"form.$_"});   $env{"form.$_"}=&unescape($env{"form.$_"});
  $ENV{"form.$_"}=~s/[^\w\/\s\(\)\=\-\"\']//g;   $env{"form.$_"}=~s/[^\w\/\s\(\)\=\-\"\']//g;
     }      }
       my ($libraries_to_query,$pretty_domains_string) = &parse_domain_restrictions();
     # Check to see if enough is filled in      #
     unless (&filled($ENV{'form.basicexp'})) {      # Check to see if enough of a query is filled in
       my $search_string = $env{'form.basicexp'};
       if (! &filled($search_string)) {
  &output_blank_field_error($r,$closebutton,'phase=disp_basic');   &output_blank_field_error($r,$closebutton,'phase=disp_basic');
  return OK;   return OK;
     }      }
     my $pretty_search_string = '<b>'.$ENV{'form.basicexp'}.'</b>';      my $pretty_search_string=$search_string;
     my $search_string = $ENV{'form.basicexp'};      my @Queries;
     if ($ENV{'form.related'}) {      my @fields = ('title','author','subject','notes','abstract','keywords');
         my @New_Words;      my $searchfield;
         ($search_string,@New_Words) = &related_version($ENV{'form.basicexp'});      if ($env{'form.area'} eq 'portfolio') {
         if (@New_Words) {          $searchfield = 'concat_ws(" ",pm.'.join(',pm.',@fields).')';
             $pretty_search_string .= " with related words: <b>@New_Words</b>.";      } else {
         } else {          $searchfield = 'concat_ws(" ",'.join(',',@fields).')';
             $pretty_search_string .= " with no related words.";      }
         }      my ($error,$SQLQuery) = &process_phrase_input($search_string,
                                                       $env{'form.related'},
                                                       $searchfield);
       if ($error) {
           &output_unparsed_phrase_error($r,$closebutton,'phase=disp_basic',
                                         '','basicexp');
           return;
       }
       push(@Queries,$SQLQuery);
       #foreach my $q (@Queries) {
       #    &Apache::lonnet::logthis('    '.$q);
       #}
       my $final_query;
       if ($env{'form.area'} eq 'portfolio') {
           $final_query = 'SELECT pm.*,pa.keynum,pa.scope FROM portfolio_metadata pm, portfolio_access pa  WHERE (pm.url = pa.url AND (pa.start < UTC_TIMESTAMP() AND (pa.end IS NULL OR pa.end > UTC_TIMESTAMP())) AND '.join(" AND ",@Queries).')';
       } else {
           $final_query = 'SELECT * FROM metadata WHERE '.join(" AND ",@Queries);
       }
       #
       if ($env{'form.related'}) {
    $pretty_search_string.=' '.&mt('(including related words)');
       }
       if (defined($pretty_domains_string) && $pretty_domains_string ne '') {
           $pretty_search_string .= ' '.$pretty_domains_string;
     }      }
     # Build SQL query string based on form page  
     my $query='';  
     my $concatarg=join(',"    ",',  
        ('title', 'author', 'subject', 'notes', 'abstract',  
                         'keywords'));  
     $concatarg='title' if $ENV{'form.titleonly'};  
     $query=&build_SQL_query('concat('.$concatarg.')',$search_string);  
     $pretty_search_string .= "<br />\n";      $pretty_search_string .= "<br />\n";
     return 'select * from metadata where '.$query,$pretty_search_string;      $pretty_search_string =~ s:^<br /> and ::;
       &Apache::lonnet::logthis('simple search final query = '.$/.$final_query);
       return ($final_query,$pretty_search_string,
               $libraries_to_query);
   }
   
   
   ###############################################################
   ###############################################################
   
   my @Phrases;
   
   sub concat {
       my ($item) = @_;
       my $results = '';
       foreach (@$item) {
           if (ref($_) eq 'ARRAY') {
               $results .= join(' ',@$_);
           }
       }
       return $results;
 }  }
   
   sub process_phrase_input {
       my ($phrase,$related,$field)=@_;
       #&Apache::lonnet::logthis('phrase = :'.$phrase.':');
       my $grammar = <<'ENDGRAMMAR';
       searchphrase:
           expression /^\Z/ {
               # &Apache::lonsearchcat::print_item(\@item,0);
               [@item];
           }
       expression:
           phrase(s)   {
               [@item];
           }
       phrase:
           orword {
               [@item];
           }
         | andword {
               [@item];
           }
         | minusword {
               unshift(@::Phrases,$item[1]->[0]);
               unshift(@::Phrases,$item[1]->[1]);
               [@item];
           }
         | word {
               unshift(@::Phrases,$item[1]);
               [@item];
           } 
       #
       orword:
           word 'OR' phrase {
               unshift(@::Phrases,'OR');
               unshift(@::Phrases,$item[1]);
               [@item];
           }
           | word 'or' phrase {
               unshift(@::Phrases,'OR');
               unshift(@::Phrases,$item[1]);
               [@item];
           }    
           | minusword 'OR' phrase {
               unshift(@::Phrases,'OR');
               unshift(@::Phrases,$item[1]->[0]);
               unshift(@::Phrases,$item[1]->[1]);
               [@item];
           }
           | minusword 'or' phrase {
               unshift(@::Phrases,'OR');
               unshift(@::Phrases,$item[1]->[0]);
               unshift(@::Phrases,$item[1]->[1]);
               [@item];
           }    
       andword:
           word phrase {
               unshift(@::Phrases,'AND');
               unshift(@::Phrases,$item[1]);
               [@item];
           }
           | minusword phrase {
               unshift(@::Phrases,'AND');
               unshift(@::Phrases,$item[1]->[0]);
               unshift(@::Phrases,$item[1]->[1]);
               [@item];
           }
       #
       minusword:
           '-' word {
               [$item[2],'NOT'];
           }
       word:
           "'" term(s) "'" {
             &Apache::lonsearchcat::concat(\@item);
           }
         | '"' term(s) '"' {
             &Apache::lonsearchcat::concat(\@item);
           }
         | term {
               $item[1];
           }
       term:
           /[\w\Q:!@#$%^&*()+_=|{}<>,.;\\\/?\E\-]+/ {
               $item[1];
           }
   ENDGRAMMAR
       #
       # The end result of parsing the phrase with the grammar is an array
       # @::Phrases.
       # $phrase = "gene splicing" or cat -> "gene splicing","OR","cat"
       # $phrase = "genetic engineering" -dna ->
       #                      "genetic engineering","AND","NOT","dna"
       # $phrase = cat or dog -poodle -> "cat","OR","dog","AND","NOT","poodle"
       undef(@::Phrases);
       my $p = new Parse::RecDescent($grammar);
       if (! defined($p->searchphrase($phrase))) {
           &Apache::lonnet::logthis('lonsearchcat:unable to process:'.$phrase);
           return 'Unable to process phrase '.$phrase;
       }
       #
       # Go through the phrases and make sense of them.  
       # Apply modifiers NOT OR and AND to the phrases.
       my @NewPhrases;
       while(@::Phrases) {
           my $phrase = shift(@::Phrases);
           # &Apache::lonnet::logthis('phrase = '.$phrase);
           my $phrasedata;
           if ($phrase =~ /^(NOT|OR|AND)$/) {
               if ($phrase eq 'OR') {
                   $phrasedata->{'or'}++;
                   if (! @::Phrases) { $phrasedata = undef; last; }
                   $phrase = shift(@::Phrases);
               } elsif ($phrase eq 'AND') {
                   $phrasedata->{'and'}++;
                   if (! @::Phrases) { $phrasedata = undef; last; }
                   $phrase = shift(@::Phrases);
               }
               if ($phrase eq 'NOT') {
                   $phrasedata->{'negate'}++;
                   if (! @::Phrases) { $phrasedata = undef; last; }
                   $phrase = shift(@::Phrases);
               }
           }
           $phrasedata->{'phrase'} = $phrase;
           if ($related) {
               my @NewWords;
               (undef,@NewWords) = &related_version($phrasedata->{'phrase'});
               $phrasedata->{'related_words'} = \@NewWords;
           }
           push(@NewPhrases,$phrasedata);
       }
       #
       # Actually build the sql query from the phrases
       my $SQLQuery;
       foreach my $phrase (@NewPhrases) {
           my $query;
           if ($phrase->{'negate'}) {
               $query .= $field.' NOT LIKE "%'.$phrase->{'phrase'}.'%"';
           } else {
               $query .= $field.' LIKE "%'.$phrase->{'phrase'}.'%"';
           }
           foreach my $related (@{$phrase->{'related_words'}}) {
               if ($phrase->{'negate'}) {
                   $query .= ' AND '.$field.' NOT LIKE "%'.$related.'%"';
               } else {
                   $query .= ' OR '.$field.' LIKE "%'.$related.'%"';
               }
           }
           if ($SQLQuery) {
               if ($phrase->{'or'}) {
                   $SQLQuery .= ' OR ('.$query.')';
               } else {
                   $SQLQuery .= ' AND ('.$query.')';
               }
           } else {
               $SQLQuery = '('.$query.')';
           }
       }
       #
       # &Apache::lonnet::logthis("SQLQuery = $SQLQuery");
       #
       return undef,$SQLQuery;
   }
   
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
   
 =pod   =pod 
   
 =item &related_version  =item &related_version()
   
 Modifies an input string to include related words.  Words in the string  Modifies an input string to include related words.  Words in the string
 are replaced with parenthesized lists of 'OR'd words.  For example  are replaced with parenthesized lists of 'OR'd words.  For example
Line 1345  Note: Using this twice on a string is pr Line 2016  Note: Using this twice on a string is pr
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
 sub related_version {  sub related_version {
     my $search_string = shift;      my ($word) = @_;
     my $result = $search_string;      return (undef) if (lc($word) =~ /\b(or|and|not)\b/);
     my %New_Words = ();      my @Words = &Apache::loncommon::get_related_words($word);
     while ($search_string =~ /(\w+)/cg) {      # Only use 4 related words
         my $word = $1;      @Words = ($#Words>4? @Words[0..4] : @Words);
         next if (lc($word) =~ /\b(or|and|not)\b/);      my $result = join " OR ", ($word,@Words);
         my @Words = &Apache::loncommon::get_related_words($word);      return $result,sort(@Words);
         @Words = ($#Words>4? @Words[0..4] : @Words);  
         foreach (@Words) { $New_Words{$_}++;}  
         my $replacement = join " OR ", ($word,@Words);  
         $result =~ s/(\b)$word(\b)/$1($replacement)$2/g;  
     }  
     return $result,sort(keys(%New_Words));  
 }  }
   
 ######################################################################  
 ######################################################################  
   
 =pod   
   
 =item &build_SQL_query()   
   
 Builds a SQL query string from a logical expression with AND/OR keywords  
 using Text::Query and &recursive_SQL_query_builder()  
   
 =cut  
   
 ######################################################################  
 ######################################################################  
 sub build_SQL_query {  
     my ($field_name,$logic_statement)=@_;  
     my $q=new Text::Query('abc',  
   -parse => 'Text::Query::ParseAdvanced',  
   -build => 'Text::Query::Build');  
     $q->prepare($logic_statement);  
     my $matchexp=${$q}{'matchexp'}; chomp $matchexp;  
     my $sql_query=&recursive_SQL_query_build($field_name,$matchexp);  
     return $sql_query;  
 }  
   
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
Line 1418  sub build_custommetadata_query { Line 2059  sub build_custommetadata_query {
     return $matchexp;      return $matchexp;
 }  }
   
 ######################################################################  
 ######################################################################  
   
 =pod   
   
 =item &recursive_SQL_query_build()   
   
 Recursively constructs an SQL query.  Takes as input $dkey and $pattern.  
   
 =cut  
   
 ######################################################################  
 ######################################################################  
 sub recursive_SQL_query_build {  
     my ($dkey,$pattern)=@_;  
     my @matches=($pattern=~/(\[[^\]|\[]*\])/g);  
     return $pattern unless @matches;  
     foreach my $match (@matches) {  
  $match=~/\[ (\w+)\s(.*) \]/;  
  my ($key,$value)=($1,$2);  
  my $replacement='';  
  if ($key eq 'literal') {  
     $replacement="($dkey like \"\%$value\%\")";  
  }  
  elsif ($key eq 'not') {  
     $value=~s/like/not like/;  
 #    $replacement="($dkey not like $value)";  
     $replacement="$value";  
  }  
  elsif ($key eq 'and') {  
     $value=~/(.*[\"|\)]) ([|\(|\^].*)/;  
     $replacement="($1 AND $2)";  
  }  
  elsif ($key eq 'or') {  
     $value=~/(.*[\"|\)]) ([|\(|\^].*)/;  
     $replacement="($1 OR $2)";  
  }  
  substr($pattern,  
        index($pattern,$match),  
        length($match),  
        $replacement  
        );  
     }  
     &recursive_SQL_query_build($dkey,$pattern);  
 }  
   
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
Line 1479  Also reports errors (check for /^Incorre Line 2075  Also reports errors (check for /^Incorre
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
 sub build_date_queries {  sub build_date_queries {
     my ($cmonth1,$cday1,$cyear1,$cmonth2,$cday2,$cyear2,      my ($cafter,$cbefore,$mafter,$mbefore) = @_;
  $lmonth1,$lday1,$lyear1,$lmonth2,$lday2,$lyear2)=@_;      my ($result,$error,$pretty_string);
     my @queries;      #
     if ($cmonth1 or $cday1 or $cyear1 or $cmonth2 or $cday2 or $cyear2) {      # Verify the input
  unless ($cmonth1 and $cday1 and $cyear1 and      if (! defined($cafter) && ! defined($cbefore) &&
  $cmonth2 and $cday2 and $cyear2) {          ! defined($mafter) && ! defined($mbefore)) {
     return "Incorrect entry for the creation date.  You must specify ".          # This is an okay situation, so return undef for the error
    "a starting month, day, and year and an ending month, ".          return (undef,undef,undef);
    "day, and year.";      }
  }      if ((defined($cafter)  && ! defined($cbefore)) ||
  my $cnumeric1=sprintf("%d%2d%2d",$cyear1,$cmonth1,$cday1);          (defined($cbefore) && ! defined($cafter))) {
  $cnumeric1+=0;          # This is bad, so let them know
  my $cnumeric2=sprintf("%d%2d%2d",$cyear2,$cmonth2,$cday2);          $error = &mt('Incorrect entry for the creation date.  '.
  $cnumeric2+=0;                      'You must specify both the beginning and ending dates.');
  if ($cnumeric1>$cnumeric2) {      }
     return "Incorrect entry for the creation date.  The starting ".      if (! defined($error) && 
    "date must occur before the ending date.";          ((defined($mafter)  && ! defined($mbefore)) ||
  }          (defined($mbefore) && ! defined($mafter)))) {
  my $cquery="(creationdate BETWEEN '$cyear1-$cmonth1-$cday1' AND '".          # This is also bad, so let them know
            "$cyear2-$cmonth2-$cday2 23:59:59')";          $error = &mt('Incorrect entry for the last revision date.  '.
  push @queries,$cquery;                       'You must specify both the beginning and ending dates.');
     }  
     if ($lmonth1 or $lday1 or $lyear1 or $lmonth2 or $lday2 or $lyear2) {  
  unless ($lmonth1 and $lday1 and $lyear1 and  
  $lmonth2 and $lday2 and $lyear2) {  
     return "Incorrect entry for the last revision date.  You must ".  
    "specify a starting month, day, and year and an ending ".  
    "month, day, and year.";  
  }  
  my $lnumeric1=sprintf("%d%2d%2d",$lyear1,$lmonth1,$lday1);  
  $lnumeric1+=0;  
  my $lnumeric2=sprintf("%d%2d%2d",$lyear2,$lmonth2,$lday2);  
  $lnumeric2+=0;  
  if ($lnumeric1>$lnumeric2) {  
     return "Incorrect entry for the last revision date.  The ".  
    "starting date must occur before the ending date.";  
  }  
  my $lquery="(lastrevisiondate BETWEEN '$lyear1-$lmonth1-$lday1' AND '".  
            "$lyear2-$lmonth2-$lday2 23:59:59')";  
  push @queries,$lquery;  
     }      }
     if (@queries) {      if (! defined($error)) {
  return join(" AND ",@queries);          #
           # Build the queries
           my @queries;
           if (defined($cbefore) && defined($cafter)) {
               my (undef,undef,undef,$caday,$camon,$cayear) = localtime($cafter);
               my (undef,undef,undef,$cbday,$cbmon,$cbyear) = localtime($cbefore);
               # Correct for year being relative to 1900
               $cayear+=1900; $cbyear+=1900;
               my $cquery=
                   '(creationdate BETWEEN '.
                   "'".$cayear.'-'.$camon.'-'.$caday."'".
                   ' AND '.
                   "'".$cbyear.'-'.$cbmon.'-'.$cbday." 23:59:59')";
               $pretty_string .= '<br />' if (defined($pretty_string));
               $pretty_string .= 
                   &mt('created between [_1] and [_2]',
                       &Apache::lonlocal::locallocaltime($cafter),
                       &Apache::lonlocal::locallocaltime($cbefore+24*60*60-1));
               push(@queries,$cquery);
               $pretty_string =~ s/ 00:00:00//g;
           }
           if (defined($mbefore) && defined($mafter)) {
               my (undef,undef,undef,$maday,$mamon,$mayear) = localtime($mafter);
               my (undef,undef,undef,$mbday,$mbmon,$mbyear) = localtime($mbefore);
               # Correct for year being relative to 1900
               $mayear+=1900; $mbyear+=1900;
               my $mquery=
                   '(lastrevisiondate BETWEEN '.
                   "'".$mayear.'-'.$mamon.'-'.$maday."'".
                   ' AND '.
                   "'".$mbyear.'-'.$mbmon.'-'.$mbday." 23:59:59')";
               push(@queries,$mquery);
               $pretty_string .= '<br />' if (defined($pretty_string));
               $pretty_string .= 
                   &mt('last revised between [_1] and [_2]',
                       &Apache::lonlocal::locallocaltime($mafter),
                       &Apache::lonlocal::locallocaltime($mbefore+24*60*60-1));
               $pretty_string =~ s/ 00:00:00//g;
           }
           if (@queries) {
               $result .= join(" AND ",@queries);
           }
     }      }
     return '';      return ($result,$error,$pretty_string);
 }  }
   
 ######################################################################  ######################################################################
Line 1533  sub build_date_queries { Line 2151  sub build_date_queries {
   
 =item &copyright_check()  =item &copyright_check()
   
   Inputs: $Metadata, a hash pointer of metadata for a resource.
   
   Returns: 1 if the resource is available to the user making the query, 
            0 otherwise.
   
 =cut  =cut
   
 ######################################################################  ######################################################################
Line 1544  sub copyright_check { Line 2167  sub copyright_check {
                                               $Metadata->{'url'});                                                $Metadata->{'url'});
     # Check for priv      # Check for priv
     if (($Metadata->{'copyright'} eq 'priv') &&       if (($Metadata->{'copyright'} eq 'priv') && 
         (($ENV{'user.name'} ne $resname) &&          (($env{'user.name'} ne $resname) &&
          ($ENV{'user.domain'} ne $resdom))) {           ($env{'user.domain'} ne $resdom))) {
         return 0;          return 0;
     }      }
     # Check for domain      # Check for domain
     if (($Metadata->{'copyright'} eq 'domain') &&      if (($Metadata->{'copyright'} eq 'domain') &&
         ($ENV{'user.domain'} ne $resdom)) {          ($env{'user.domain'} ne $resdom)) {
         return 0;          return 0;
     }      }
       # Check for custom rights
       if ($Metadata->{'copyright'} eq 'custom') {
          return &Apache::lonnet::customaccess('bre',$Metadata->{'url'});
       }
     return 1;      return 1;
 }  }
   
   
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
   
 =pod  =pod
   
 =item &ensure_db_and_table  =item &ensure_db_and_table()
   
 Ensure we can get lonmysql to connect to the database and the table we  Ensure we can get lonmysql to connect to the database and the table we
 need exists.  need exists.
Line 1581  sub ensure_db_and_table { Line 2207  sub ensure_db_and_table {
     ## Sanity check the table id.      ## Sanity check the table id.
     ##      ##
     if (! defined($table) || $table eq '' || $table =~ /\D/ ) {      if (! defined($table) || $table eq '' || $table =~ /\D/ ) {
         $r->print("Unable to retrieve search results.  ".          $r->print(&Apache::loncommon::start_page(&mt('Error'))
                   "Unable to determine the table results were stored in.  ".  . '<p>table: |'.$table.'|</p>' # SB
                   "</body></html>");                   .'<p class="LC_error">'
                    .&mt('Unable to retrieve search results. '
                        .'Unable to determine the table results were saved in.')
                    .&Apache::loncommon::end_page()
           );
         return undef;          return undef;
     }      }
     ##      ##
Line 1592  sub ensure_db_and_table { Line 2222  sub ensure_db_and_table {
     my $connection_result = &Apache::lonmysql::connect_to_db();      my $connection_result = &Apache::lonmysql::connect_to_db();
     if (!defined($connection_result)) {      if (!defined($connection_result)) {
         $r->print("Unable to connect to the MySQL database where your results".          $r->print("Unable to connect to the MySQL database where your results".
                   " are stored. </body></html>");                    " are saved.".
     &Apache::loncommon::end_page());
         &Apache::lonnet::logthis("lonsearchcat: unable to get lonmysql to".          &Apache::lonnet::logthis("lonsearchcat: unable to get lonmysql to".
                                  " connect to database.");                                   " connect to database.");
         &Apache::lonnet::logthis(&Apache::lonmysql::get_error());          &Apache::lonnet::logthis(&Apache::lonmysql::get_error());
Line 1600  sub ensure_db_and_table { Line 2231  sub ensure_db_and_table {
     }      }
     my $table_check = &Apache::lonmysql::check_table($table);      my $table_check = &Apache::lonmysql::check_table($table);
     if (! defined($table_check)) {      if (! defined($table_check)) {
         $r->print("A MySQL error has occurred.</form></body></html>");          $r->print("A MySQL error has occurred.</form>".
     &Apache::loncommon::end_page());
         &Apache::lonnet::logthis("lonmysql was unable to determine the status".          &Apache::lonnet::logthis("lonmysql was unable to determine the status".
                                  " of table ".$table);                                   " of table ".$table);
         return undef;          return undef;
Line 1618  sub ensure_db_and_table { Line 2250  sub ensure_db_and_table {
   
 =pod  =pod
   
 =item &print_sort_form  =item &print_sort_form()
   
   The sort feature is not implemented at this time.  This form just prints 
   a link to change the search query.
   
 =cut  =cut
   
Line 1626  sub ensure_db_and_table { Line 2261  sub ensure_db_and_table {
 ######################################################################  ######################################################################
 sub print_sort_form {  sub print_sort_form {
     my ($r,$pretty_query_string) = @_;      my ($r,$pretty_query_string) = @_;
   
     ##      ##
     my %SortableFields =       my %SortableFields=&Apache::lonlocal::texthash( 
         (id        => 'Default',           id        => 'Default',
          title     => 'Title',           title     => 'Title',
          author    => 'Author',           author    => 'Author',
          subject   => 'Subject',           subject   => 'Subject',
Line 1640  sub print_sort_form { Line 2276  sub print_sort_form {
          copyright => 'Copyright',           copyright => 'Copyright',
          hostname  => 'Host',           hostname  => 'Host',
          creationdate     => 'Creation Date',           creationdate     => 'Creation Date',
          lastrevisiondate => 'Revision Date',           lastrevisiondate => 'Revision Date'
      );       );
     ##      ##
     my $table = $ENV{'form.table'};      my $table = $env{'form.table'};
     return if (! &ensure_db_and_table($r,$table));      return if (! &ensure_db_and_table($r,$table));
     ##      ##
     ## Get the number of results       ## Get the number of results 
     ##      ##
     my $total_results = &Apache::lonmysql::number_of_rows($table);      my $total_results = &Apache::lonmysql::number_of_rows($table);
     if (! defined($total_results)) {      if (! defined($total_results)) {
         $r->print("A MySQL error has occurred.</form></body></html>");          $r->print("A MySQL error has occurred.</form>".
     &Apache::loncommon::end_page());
         &Apache::lonnet::logthis("lonmysql was unable to determine the number".          &Apache::lonnet::logthis("lonmysql was unable to determine the number".
                                  " of rows in table ".$table);                                   " of rows in table ".$table);
         &Apache::lonnet::logthis(&Apache::lonmysql::get_error());          &Apache::lonnet::logthis(&Apache::lonmysql::get_error());
         return;          return;
     }      }
     my $result;      my $js =<<END;
     $result.=<<END;  <script type="text/javascript">
 <html>  // <![CDATA[
 <head>  
 <script>  
     function change_sort() {      function change_sort() {
         var newloc = "/adm/searchcat?phase=results";          var newloc = "/adm/searchcat?phase=results";
         newloc += "&persistent_db_id=$ENV{'form.persistent_db_id'}";          newloc += "&amp;persistent_db_id=$env{'form.persistent_db_id'}";
         newloc += "&sortby=";          newloc += "&amp;sortby=";
         newloc += document.forms.statusform.elements.sortby.value;          newloc += document.forms.statusform.elements.sortby.value;
         parent.resultsframe.location= newloc;          parent.resultsframe.location= newloc;
     }      }
   // ]]>
 </script>  </script>
 <title>Results</title>  END
 </head>  
 <body>      my $start_page = &Apache::loncommon::start_page('Results',$js);
 <form name="statusform" action="" method="post">      my $breadcrumbs=
 <input type="hidden" name="Queue" value="" />          &Apache::lonhtmlcommon::breadcrumbs('Searching','Searching',
       $env{'form.catalogmode'} ne 'import');
   
       my $result = <<END;
   $start_page
   $breadcrumbs
   <form name="statusform" action="" method="post" target="_top">
   <input type="hidden" name="catalogmode" value="import" />
   <input type="hidden" name="acts" value="" />
 END  END
   
 #<h2>Sort Results</h2>  #<h2>Sort Results</h2>
 #Sort by: <select size="1" name="sortby" onchange="javascript:change_sort();">  #Sort by: <select size="1" name="sortby" onchange="javascript:change_sort();">
 #    $ENV{'form.sortby'} = 'id' if (! defined($ENV{'form.sortby'}));  #    $env{'form.sortby'} = 'id' if (! defined($env{'form.sortby'}));
 #    foreach (keys(%SortableFields)) {  #    foreach (keys(%SortableFields)) {
 #        $result.="<option name=\"$_\"";  #        $result.="<option name=\"$_\"";
 #        if ($_ eq $ENV{'form.sortby'}) {  #        if ($_ eq $env{'form.sortby'}) {
 #            $result.=" selected ";  #            $result.=" selected ";
 #        }  #        }
 #        $result.=" >$SortableFields{$_}</option>\n";  #        $result.=" >$SortableFields{$_}</option>\n";
 #    }  #    }
 #    $result.="</select>\n";  #    $result.="</select>\n";
     my $revise = &revise_button();      my $revise = &revise_button();
     $result.=<<END;      $result.='<p>'
 <p>              .&mt('There are [_1] matches to your query.',$total_results)
 There are $total_results matches to your query. $revise              .' '.$revise.'</p>'
 </p><p>              .'<p>'.&mt('Search: ').$pretty_query_string
 Search:$pretty_query_string              .'</p></form>';
 </p>      $r->print($result.&Apache::loncommon::end_page());
 </form>  
 </body>  
 </html>  
 END  
     $r->print($result);  
     return;      return;
 }  }
   
Line 1716  the following format: Line 2355  the following format:
   
 =cut  =cut
   
 ##  #####################################################################
 ## Restrictions:  #####################################################################
 ##    columns of type 'text' and 'blob' cannot have defaults.  #
 ##    columns of type 'enum' cannot be used for FULLTEXT.  # These should probably be scoped but I don't have time right now...
 ##  #
 my @DataOrder = qw/id title author subject url keywords version notes  my @Datatypes;
     abstract mime lang owner copyright creationdate lastrevisiondate hostname/;  my @Fullindicies;
   
 my %Datatypes =   
     ( id        =>{ type         => 'MEDIUMINT',  
                     restrictions => 'UNSIGNED NOT NULL',  
                     primary_key  => 'yes',  
                     auto_inc     => 'yes'  
                     },  
       title     =>{ type=>'TEXT'},  
       author    =>{ type=>'TEXT'},  
       subject   =>{ type=>'TEXT'},  
       url       =>{ type=>'TEXT',  
                     restrictions => 'NOT NULL' },  
       keywords  =>{ type=>'TEXT'},  
       version   =>{ type=>'TEXT'},  
       notes     =>{ type=>'TEXT'},  
       abstract  =>{ type=>'TEXT'},  
       mime      =>{ type=>'TEXT'},  
       lang      =>{ type=>'TEXT'},  
       owner     =>{ type=>'TEXT'},  
       copyright =>{ type=>'TEXT'},  
       hostname  =>{ type=>'TEXT'},  
       #--------------------------------------------------  
       creationdate     =>{ type=>'DATETIME'},  
       lastrevisiondate =>{ type=>'DATETIME'},  
       #--------------------------------------------------  
       );  
   
 my @Fullindicies =   
     qw/title/;  
 #    qw/title author subject abstract mime language owner copyright/;  
           
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
Line 1762  my @Fullindicies = Line 2371  my @Fullindicies =
 =item &create_results_table()  =item &create_results_table()
   
 Creates the table of search results by calling lonmysql.  Stores the  Creates the table of search results by calling lonmysql.  Stores the
 table id in $ENV{'form.table'}  table id in $env{'form.table'}
   
 Inputs: none.  Inputs: search area - either res or portfolio 
   
 Returns: the identifier of the table on success, undef on error.  Returns: the identifier of the table on success, undef on error.
   
Line 1772  Returns: the identifier of the table on Line 2381  Returns: the identifier of the table on
   
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
   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 {  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      my $table = &Apache::lonmysql::create_table
         ( { columns => \%Datatypes,          ( { columns => \@Datatypes,
             column_order => \@DataOrder,              FULLTEXT => [{'columns' => \@Fullindicies},],
             fullindex => \@Fullindicies,  
         } );          } );
     if (defined($table)) {      if (defined($table)) {
         $ENV{'form.table'} = $table;          $env{'form.table'} = $table;
         return $table;          return $table;
     }       } 
     return undef; # Error...      return undef; # Error...
Line 1817  Returns: Nothing. Line 2446  Returns: Nothing.
 sub update_count_status {  sub update_count_status {
     my ($r,$text) = @_;      my ($r,$text) = @_;
     $text =~ s/\'/\\\'/g;      $text =~ s/\'/\\\'/g;
     $r->print      $r->print(<<SCRIPT);
         ("<script>document.statusform.count.value = ' $text'</script>\n");  <script type="text/javascript">
   // <![CDATA[
   document.statusform.count.value = ' $text'
   // ]]>
   </script>
   SCRIPT
   
     $r->rflush();      $r->rflush();
 }  }
   
 sub update_status {  sub update_status {
     my ($r,$text) = @_;      my ($r,$text) = @_;
     $text =~ s/\'/\\\'/g;      $text =~ s/\'/\\\'/g;
     $r->print      $r->print(<<SCRIPT);
         ("<script>document.statusform.status.value = ' $text'</script>\n");  <script type="text/javascript">
   // <![CDATA[
   document.statusform.status.value = ' $text'
   // ]]>
   </script>
   SCRIPT
   
     $r->rflush();      $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 {  sub update_seconds {
     my ($r,$text) = @_;      my ($r) = @_;
     $text =~ s/\'/\\\'/g;      my $time = &time_left();
     $r->print      if (($last_time-$time) > 0) {
         ("<script>document.statusform.seconds.value = ' $text'</script>\n");          $r->print(<<SCRIPT);
     $r->rflush();  <script type="text/javascript">
   // <![CDATA[
   document.statusform.seconds.value = '$time'
   // ]]>
   </script>
   SCRIPT
   
           $r->rflush();
       }
       $last_time = $time;
   }
   
 }  }
   
 ######################################################################  ######################################################################
Line 1843  sub update_seconds { Line 2514  sub update_seconds {
   
 =pod  =pod
   
 =item &revise_button  =item &revise_button()
   
 Inputs: None  Inputs: None
   
Line 1854  Returns: html string for a 'revise searc Line 2525  Returns: html string for a 'revise searc
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
 sub revise_button {  sub revise_button {
       my $revisetext = &mt('Revise search');
     my $revise_phase = 'disp_basic';      my $revise_phase = 'disp_basic';
     $revise_phase = 'disp_adv' if ($ENV{'form.searchmode'} eq 'advanced');      $revise_phase = 'disp_adv' if ($env{'form.searchmode'} eq 'advanced');
     my $newloc = '/adm/searchcat'.      my $newloc = '/adm/searchcat'.
         '?persistent_db_id='.$ENV{'form.persistent_db_id'}.          '?persistent_db_id='.$env{'form.persistent_db_id'}.
             '&phase='.$revise_phase;              '&amp;cleargroupsort=1'.
     my $result = qq{<input type="button" value="Revise search" name="revise"} .              '&amp;phase='.$revise_phase;
         qq{ onClick="parent.location='$newloc';" /> };      my $result = qq{<input type="button" value="$revisetext" name="revise"} .
           qq{ onclick="parent.location='$newloc';" /> };
     return $result;      return $result;
 }  }
   
Line 1869  sub revise_button { Line 2542  sub revise_button {
   
 =pod  =pod
   
 =item &run_search   =item &run_search()
   
   Executes a search query by sending it the the other servers and putting the
   results into MySQL.
   
 =cut  =cut
   
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
 sub run_search {  sub run_search {
     my ($r,$query,$customquery,$customshow,$serverlist,$pretty_string) = @_;      my ($r,$query,$customquery,$customshow,$serverlist,
           $pretty_string,$area) = @_;
       my $tabletype = 'metadata';
       if ($area eq 'portfolio') {
           $tabletype = 'portfolio_search';
       }
     my $connection = $r->connection;      my $connection = $r->connection;
     #      #
     # Timing variables  
     #  
     my $starttime = time;  
     my $max_time  = 30;  # seconds for the search to complete  
     #  
     # Print run_search header      # Print run_search header
     #      #
       my $start_page = &Apache::loncommon::start_page('Search Status',undef);
       my $breadcrumbs =
    &Apache::lonhtmlcommon::breadcrumbs('Searching','Searching',
       $env{'form.catalogmode'} ne 'import');
     $r->print(<<END);      $r->print(<<END);
 <html>  $start_page
 <head><title>Search Status</title></head>  $breadcrumbs
 <body>  
 <form name="statusform" action="" method="post">  
 <input type="hidden" name="Queue" value="" />  
 END  END
     # Check to see if $pretty_string has more than one carriage return.      # Remove leading and trailing <br />
     # Assume \n s are following <br /> s and truncate the value.      $pretty_string =~ s:^\s*<br />::i;
     # (there is probably a better way)...      $pretty_string =~ s:(<br />)*\s*$::im;
     my @Lines = split /<br \/>/,$pretty_string;      my @Lines = split("<br />",$pretty_string);
       # I keep getting blank items at the end of the list, hence the following:
       while ($Lines[-1] =~ /^\s*$/ && @Lines) {
           pop(@Lines);
       }
     if (@Lines > 2) {      if (@Lines > 2) {
         $pretty_string = join '<br \>',(@Lines[0..2],'....<br />');          $pretty_string = join '<br />',(@Lines[0..2],'...<br />');
     }      }
     $r->print("Search: ".$pretty_string);      $r->print(&mt("Search: [_1]",$pretty_string));
     $r->rflush();      $r->rflush();
     #      #
     # Determine the servers we need to contact.      # Determine the servers we need to contact.
     #  
     my @Servers_to_contact;      my @Servers_to_contact;
     if (defined($serverlist)) {      if (defined($serverlist)) {
         if (ref($serverlist) eq 'ARRAY') {          if (ref($serverlist) eq 'ARRAY') {
Line 1913  END Line 2593  END
             @Servers_to_contact = ($serverlist);              @Servers_to_contact = ($serverlist);
         }          }
     } else {      } else {
         @Servers_to_contact = sort(keys(%Apache::lonnet::libserv));   my %all_library_servers = &Apache::lonnet::all_library();
           @Servers_to_contact = sort(keys(%all_library_servers));
     }      }
     my %Server_status;      my %Server_status;
     my $table =$ENV{'form.table'};      #
       # Check on the mysql table we will use to store results.
       my $table =$env{'form.table'};
     if (! defined($table) || $table eq '' || $table =~ /\D/ ) {      if (! defined($table) || $table eq '' || $table =~ /\D/ ) {
         $r->print("Unable to determine table id to store search results in.".          $r->print("Unable to determine table id to save search results in.".
                   "The search has been aborted.</body></html>");                    "The search has been aborted.".
     &Apache::loncommon::end_page());
         return;          return;
     }      }
     my $table_status = &Apache::lonmysql::check_table($table);      my $table_status = &Apache::lonmysql::check_table($table);
     if (! defined($table_status)) {      if (! defined($table_status)) {
         $r->print("Unable to determine status of table.</body></html>");          $r->print("Unable to determine status of table.".
     &Apache::loncommon::end_page());
         &Apache::lonnet::logthis("Bogus table id of $table for ".          &Apache::lonnet::logthis("Bogus table id of $table for ".
                                  "$ENV{'user.name'} @ $ENV{'user.domain'}");                                   "$env{'user.name'} @ $env{'user.domain'}");
         &Apache::lonnet::logthis("lonmysql error = ".          &Apache::lonnet::logthis("lonmysql error = ".
                                  &Apache::lonmysql::get_error());                                   &Apache::lonmysql::get_error());
         return;          return;
     }      }
     if (! $table_status) {      if (! $table_status) {
           &Apache::lonnet::logthis("lonmysql error = ".
                                    &Apache::lonmysql::get_error());
           &Apache::lonnet::logthis("lonmysql debug = ".
                                    &Apache::lonmysql::get_debug());
           &Apache::lonnet::logthis('table status = "'.$table_status.'"');
         $r->print("The table id,$table, we tried to use is invalid.".          $r->print("The table id,$table, we tried to use is invalid.".
                   "The search has been aborted.</body></html>");                    "The search has been aborted.".
     &Apache::loncommon::end_page());
         return;          return;
     }      }
     ##      ##
     ## Prepare for the big loop.      ## Prepare for the big loop.
     ##  
     my $hitcountsum;      my $hitcountsum;
       my %matches;
     my $server;       my $server; 
     my $status;      my $status;
     my $revise = &revise_button();      my $revise = &revise_button();
     $r->print(<<END);      $r->print('<form name="statusform" action="" method="post">'."\n".
 <table>                '<input type="hidden" name="acts" value="" />'."\n".
 <tr><th>Status</th><th>Total Matches</th><th>Time Remaining</th><th></th></tr>                '<table border="0"><tr><td>'."\n".
 <tr>                &Apache::loncommon::start_data_table());
 <td><input type="text" name="status"  value="" size="30" /></td>      $r->print(&Apache::loncommon::start_data_table_header_row()
 <td><input type="text" name="count"   value="" size="10" /></td>               .'<th>'.&mt('Status').'</th>'
 <td><input type="text" name="seconds" value="" size="8" /></td>               .'<th>'.&mt('Total Matches').'</th>'
 <td>$revise</td>               .'<th>'.&mt('Time Remaining').'</th>'
 </tr>               .&Apache::loncommon::end_data_table_header_row()
 </table>               .&Apache::loncommon::start_data_table_row()
 </form>               .'<td><input type="text" name="status"  value="" size="50" readonly="readonly" /></td>'
 END               .'<td><input type="text" name="count"   value="" size="10" readonly="readonly" /></td>'
                .'<td><input type="text" name="seconds" value="" size="8" readonly="readonly" /></td>'
                .&Apache::loncommon::end_data_table_row()
                .&Apache::loncommon::end_data_table()
                .'</td><td>&nbsp;</td><td>'.$revise.'</td></tr></table></form>');
     $r->rflush();      $r->rflush();
     my $time_remaining = $max_time - (time - $starttime) ;      &reset_timing();
     my $last_time = $time_remaining;      &update_seconds($r);
     &update_seconds($r,$time_remaining);      &update_status($r,&mt('contacting [_1]',$Servers_to_contact[0]));
     while (($time_remaining > 0) &&       while (&time_left() &&
            ((@Servers_to_contact) || keys(%Server_status))) {             ((@Servers_to_contact) || keys(%Server_status))) {
         # Send out a search request if it needs to be done.          &update_seconds($r);
           #
           # Send out a search request
         if (@Servers_to_contact) {          if (@Servers_to_contact) {
             # Contact one server              # Contact one server
             my $server = shift(@Servers_to_contact);              my $server = shift(@Servers_to_contact);
               &update_status($r,&mt('contacting [_1]',$server));
             my $reply=&Apache::lonnet::metadata_query($query,$customquery,              my $reply=&Apache::lonnet::metadata_query($query,$customquery,
                                                       $customshow,[$server]);                                                        $customshow,[$server]);
             ($server) = keys(%$reply);              ($server) = keys(%$reply);
             $Server_status{$server} = $reply->{$server};              $Server_status{$server} = $reply->{$server};
             &update_status($r,'contacting '.$server);  
         } else {          } else {
             # wait a sec. to give time for files to be written              # wait a sec. to give time for files to be written
             # This sleep statement is here instead of outside the else               # This sleep statement is here instead of outside the else 
             # block because we do not want to pause if we have servers              # block because we do not want to pause if we have servers
             # left to contact.                # left to contact.  
               if (scalar (keys(%Server_status))) {
                   &update_status($r,
                          &mt('waiting on [_1]',join(' ',keys(%Server_status))));
               }
             sleep(1)              sleep(1)
         }          }
         &update_status($r,'waiting on '.(join(' ',keys(%Server_status))));          #
         while (my ($server,$status) = each(%Server_status)) {          # Loop through the servers we have contacted but do not
           # have results from yet, looking for results.
           foreach my $server (keys(%Server_status)) {
             last if ($connection->aborted());              last if ($connection->aborted());
               &update_seconds($r);
               my $status = $Server_status{$server};
             if ($status eq 'con_lost') {              if ($status eq 'con_lost') {
                 delete ($Server_status{$server});                  delete ($Server_status{$server});
                 next;                  next;
             }              }
             $status=~/^([\.\w]+)$/;               $status=~s|/||g;
            my $datafile=$r->dir_config('lonDaemons').'/tmp/'.$1;             my $datafile=$r->dir_config('lonDaemons').'/tmp/'.$status;
             if (-e $datafile && ! -e "$datafile.end") {              if (-e $datafile && ! -e "$datafile.end") {
                 &update_status($r,'Receiving results from '.$server);                  &update_status($r,&mt('Receiving results from [_1]',$server));
                 next;                  next;
             }              }
             last if ($connection->aborted());              last if ($connection->aborted());
             if (-e "$datafile.end") {              if (-e "$datafile.end") {
                 &update_status($r,'Reading results from '.$server);                  &update_status($r,&mt('Reading results from [_1]',$server));
                 if (-z "$datafile") {                  if (-z "$datafile") {
                     delete($Server_status{$server});                      delete($Server_status{$server});
                     next;                      next;
Line 2007  END Line 2712  END
                 # Read in the whole file.                  # Read in the whole file.
                 while (my $result = <$fh>) {                  while (my $result = <$fh>) {
                     last if ($connection->aborted());                      last if ($connection->aborted());
                     # handle custom fields?  Someday we will!                      #
                       # Records are stored one per line
                     chomp($result);                      chomp($result);
                     next unless $result;                      next if (! $result);
                       #
                     # Parse the result.                      # Parse the result.
                     my %Fields = &parse_raw_result($result,$server);                      my %Fields = &parse_raw_result($result,$server,$tabletype);
                     $Fields{'hostname'} = $server;                      $Fields{'hostname'} = $server;
                       #
                       # Skip based on copyright
                     next if (! &copyright_check(\%Fields));                      next if (! &copyright_check(\%Fields));
   
                       if ($area eq 'portfolio') {
                           next if (defined($matches{$Fields{'url'}}));
                           # Skip if inaccessible
                           next if (!&Apache::lonnet::portfolio_access($Fields{'url'}));
                           $matches{$Fields{'url'}} = 1; 
                       }
                       #
                     # Store the result in the mysql database                      # Store the result in the mysql database
                     my $result = &Apache::lonmysql::store_row($table,\%Fields);                      my $result = &Apache::lonmysql::store_row($table,\%Fields);
                     if (! defined($result)) {                      if (! defined($result)) {
                         $r->print(&Apache::lonmysql::get_error());                          $r->print(&Apache::lonmysql::get_error());
                     }                      }
                     # $r->print(&Apache::lonmysql::get_debug());                      #
                     $hitcountsum ++;                      $hitcountsum ++;
                     $time_remaining = $max_time - (time - $starttime) ;                      &update_seconds($r);
                     if ($last_time - $time_remaining > 0) {  
                         &update_seconds($r,$time_remaining);  
                         $last_time = $time_remaining;  
                     }  
                     if ($hitcountsum % 50 == 0) {                      if ($hitcountsum % 50 == 0) {
                         &update_count_status($r,$hitcountsum);                          &update_count_status($r,$hitcountsum);
                     }                      }
                 } # End of foreach (@results)                  }
                 $fh->close();                  $fh->close();
                 # $server is only deleted if the results file has been                   # $server is only deleted if the results file has been 
                 # found and (successfully) opened.  This may be a bad idea.                  # found and (successfully) opened.  This may be a bad idea.
Line 2039  END Line 2752  END
             &update_count_status($r,$hitcountsum);              &update_count_status($r,$hitcountsum);
         }          }
         last if ($connection->aborted());          last if ($connection->aborted());
         # Finished looping through the servers          &update_seconds($r);
         $time_remaining = $max_time - (time - $starttime) ;  
         if ($last_time - $time_remaining > 0) {  
             $last_time = $time_remaining;  
             &update_seconds($r,$time_remaining);  
         }  
     }      }
     &update_status($r,'Search Complete'.$server);      &update_status($r,&mt('Search Complete on Server [_1]',$server));
     &update_seconds($r,0);      &update_seconds($r);
     &Apache::lonmysql::disconnect_from_db();      #
       &Apache::lonmysql::disconnect_from_db(); # This is unneccessary
       #
     # We have run out of time or run out of servers to talk to and      # We have run out of time or run out of servers to talk to and
     # results to get.        # results to get, so let the client know the top frame needs to be
     $r->print("</body></html>");      # loaded from /adm/searchcat
     if ($ENV{'form.catalogmode'} ne 'groupsearch') {      $r->print(&Apache::loncommon::end_page());
         $r->print("<script>".  #    if ($env{'form.catalogmode'} ne 'import') {
                       "window.location='/adm/searchcat?".           $r->print(<<SCRIPT);
                       "phase=sort&".  <script>
                       "persistent_db_id=$ENV{'form.persistent_db_id'}';".  window.location='/adm/searchcat?phase=sort&persistent_db_id=$env{'form.persistent_db_id'}';
                   "</script>");  </script>
     }  SCRIPT
   #    }
     return;      return;
 }  }
   
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
   
 =pod  =pod
   
 =item &prev_next_buttons  =item &prev_next_buttons()
   
   Returns html for the previous and next buttons on the search results page.
   
 =cut  =cut
   
Line 2075  END Line 2789  END
 sub prev_next_buttons {  sub prev_next_buttons {
     my ($current_min,$show,$total,$parms) = @_;      my ($current_min,$show,$total,$parms) = @_;
     return '' if ($show eq 'all'); # No links if you get them all at once.      return '' if ($show eq 'all'); # No links if you get them all at once.
     my $links;      #
     ##      # Create buttons
     ## Prev      return '<p class="LC_nobreak">'
     my $prev_min = $current_min - $show;            .'<input type="submit" name="prev" value="&lt;"'
     $prev_min = 1 if $prev_min < 1;            .' title="'.&mt('Previous').'" />'
     if ($prev_min < $current_min) {            .' '
         $links .= qq{            .'<input type="submit" name="reload" value="'.&mt('Reload').'" />'
 <a href="/adm/searchcat?$parms&start=$prev_min&show=$show">prev</a>            .' '
 };                .'<input type="submit" name="next" value="&gt;"'
     } else {            .' title="'.&mt('Next').'" />'
         $links .= 'prev';            .'</p>';
     }  
     ##  
     ## Pages.... Someday.  
     ##  
     $links .= qq{ &nbsp;  
 <a href="/adm/searchcat?$parms&start=$current_min&$show=$show">reload</a>  
 };  
     ##  
     ## Next  
     my $next_min = $current_min + $show;  
     $next_min = $current_min if ($next_min > $total);  
     if ($next_min != $current_min) {  
         $links .= qq{ &nbsp;  
 <a href="/adm/searchcat?$parms&start=$next_min&show=$show">next</a>  
 };      
     } else {  
         $links .= '&nbsp;next';  
     }  
     return $links;  
 }  }
   
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
   
 =pod  =pod
   
 =item &display_results  =item &display_results()
   
   Prints the results out for selection and perusal.
   
 =cut  =cut
   
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
 sub display_results {  sub display_results {
     my ($r,$importbutton,$closebutton) = @_;      my ($r,$importbutton,$closebutton,$diropendb,$area) = @_;
     my $connection = $r->connection;      my $connection = $r->connection;
     $r->print(&search_results_header($importbutton,$closebutton));      $r->print(&search_results_header($importbutton,$closebutton));
     ##      ##
     ## Set viewing function      ## Set viewing function
     ##      ##
     my $viewfunction = $Views{$ENV{'form.viewselect'}};      my $viewfunction = $Views{$env{'form.viewselect'}};
     if (!defined($viewfunction)) {      if (!defined($viewfunction)) {
         $r->print("Internal Error - Bad view selected.\n");          $r->print('<p class="LC_error">'
                    .&mt('Internal Error - Bad view selected.')
                    .'</p>'."\n");
         $r->rflush();          $r->rflush();
         return;          return;
     }      }
     ##      ##
       ## $checkbox_num is a count of the number of checkboxes output on the 
       ## page this is used only during catalogmode=import.
       my $checkbox_num = 0;
       ##
     ## Get the catalog controls setup      ## Get the catalog controls setup
     ##      ##
     my $action = "/adm/searchcat?phase=results";      my $action = "/adm/searchcat?phase=results";
     ##      ##
     ## Deal with groupsearch      ## Deal with import by opening the import db file.
     ##      if ($env{'form.catalogmode'} eq 'import') {
     if ($ENV{'form.catalogmode'} eq 'groupsearch') {  
         if (! tie(%groupsearch_db,'GDBM_File',$diropendb,          if (! tie(%groupsearch_db,'GDBM_File',$diropendb,
                   &GDBM_WRCREAT(),0640)) {                    &GDBM_WRCREAT(),0640)) {
             $r->print('Unable to store import results.</form></body></html>');              $r->print('<p class="LC_error">'.
                 &mt('Unable to save import results.').
                 '</p>'.
                 '</form>'.
         &Apache::loncommon::end_page());
             $r->rflush();              $r->rflush();
             return;              return;
         }           } 
     }      }
     ##      ##
     ## Prepare the table for querying      ## Prepare the table for querying
     ##      my $table = $env{'form.table'};
     my $table = $ENV{'form.table'};  
     return if (! &ensure_db_and_table($r,$table));      return if (! &ensure_db_and_table($r,$table));
     ##      ##
     ## Get the number of results       ## Get the number of results 
     ##  
     my $total_results = &Apache::lonmysql::number_of_rows($table);      my $total_results = &Apache::lonmysql::number_of_rows($table);
     if (! defined($total_results)) {      if (! defined($total_results)) {
         $r->print("A MySQL error has occurred.</form></body></html>");          $r->print('<p class="LC_error">'.
             &mt('A MySQL error has occurred.').
             '</p>'.
             '</form>'.
     &Apache::loncommon::end_page());
         &Apache::lonnet::logthis("lonmysql was unable to determine the number".          &Apache::lonnet::logthis("lonmysql was unable to determine the number".
                                  " of rows in table ".$table);                                   " of rows in table ".$table);
         &Apache::lonnet::logthis(&Apache::lonmysql::get_error());          &Apache::lonnet::logthis(&Apache::lonmysql::get_error());
Line 2163  sub display_results { Line 2872  sub display_results {
     }      }
     ##      ##
     ## Determine how many results we need to get      ## Determine how many results we need to get
     ##      $env{'form.start'} = 1  if (! exists($env{'form.start'}));
     $ENV{'form.start'} = 1      if (! exists($ENV{'form.start'}));      $env{'form.show'}  = 20 if (! exists($env{'form.show'}));
     $ENV{'form.show'}  = 'all'  if (! exists($ENV{'form.show'}));      if (exists($env{'form.prev'})) {
     my $min = $ENV{'form.start'};          $env{'form.start'} -= $env{'form.show'};
       } elsif (exists($env{'form.next'})) {
           $env{'form.start'} += $env{'form.show'};
       }
       $env{'form.start'} = 1 if ($env{'form.start'}<1);
       $env{'form.start'} = $total_results if ($env{'form.start'}>$total_results);
       my $min = $env{'form.start'};
     my $max;      my $max;
     if ($ENV{'form.show'} eq 'all') {      if ($env{'form.show'} eq 'all') {
         $max = $total_results ;          $max = $total_results ;
     } else {      } else {
         $max = $min + $ENV{'form.show'} - 1;          $max = $min + $env{'form.show'} - 1;
         $max = $total_results if ($max > $total_results);          $max = $total_results if ($max > $total_results);
     }      }
     ##      ##
     ## Output links (if necessary) for 'prev' and 'next' pages.      ## Output form elements
     ##      $r->print(&hidden_field('table').
     $r->print                &hidden_field('phase').
         ('<center>'.                &hidden_field('persistent_db_id').
          &prev_next_buttons($min,$ENV{'form.show'},$total_results,                &hidden_field('start').
                             "table=".$ENV{'form.table'}.                &hidden_field('area')
                             "&phase=results".                );
                             "&persistent_db_id=".$ENV{'form.persistent_db_id'})      #
          ."</center>\n"      # Build sorting selector
          );      my @fields = 
           (
            {key=>'default' },
            {key=>'title' },
            {key =>'author' },
            {key =>'subject'},
            {key =>'url',desc=>'URL'},
            {key =>'keywords'},
            {key =>'language'},
            {key =>'creationdate'},
            {key =>'lastrevisiondate'},
            {key =>'owner'},
            {key =>'copyright'},
            {key =>'authorspace'},
            {key =>'lowestgradelevel'},
            {key =>'highestgradelevel'},
            {key =>'standards',desc=>'Standards'},
           );
       if ($area eq 'portfolio') {
           push(@fields,
          (
            {key => 'scope'},
            {key => 'keynum'},
          ));
       } else {
           push(@fields,
          (
            {key =>'count',desc=>'Number of accesses'},
            {key =>'stdno',desc=>'Students Attempting'},
            {key =>'avetries',desc=>'Average Number of Tries'},
            {key =>'difficulty',desc=>'Mean Degree of Difficulty'},
            {key =>'disc',desc=>'Mean Degree of Discrimination'},
            {key =>'clear',desc=>'Evaluation: Clear'},
            {key =>'technical',desc=>'Evaluation: Technically Correct'},
            {key =>'correct',desc=>'Evaluation: Material is Correct'},
            {key =>'helpful',desc=>'Evaluation: Material is Helpful'},
            {key =>'depth',desc=>'Evaluation: Material has Depth'},
          ));
       }
       my %fieldnames = &Apache::lonmeta::fieldnames();
       my @field_order;
       foreach my $field_data (@fields) {
           push(@field_order,$field_data->{'key'});
           if (! exists($field_data->{'desc'})) {
               $field_data->{'desc'}=$fieldnames{$field_data->{'key'}};
           } else {
               if (! defined($field_data->{'desc'})) {
                   $field_data->{'desc'} = ucfirst($field_data->{'key'});
               }
               $field_data->{'desc'} = &mt($field_data->{'desc'});
           }
       }
       my %sort_fields = map {$_->{'key'},$_->{'desc'}} @fields;
       $sort_fields{'select_form_order'} = \@field_order;
       $env{'form.sortorder'} = 'desc' if (! exists($env{'form.sortorder'}));
       if (! exists($env{'form.sortfield'})) {
           if ($area eq 'portfolio') {
               $env{'form.sortfield'} = 'owner';
           } else {
               $env{'form.sortfield'} = 'count';
           }
       }
       if (! exists($env{'form.sortorder'})) {
    if ($env{'form.sortfield'}=~/^(count|stdno|disc|clear|technical|correct|helpful)$/) {
       $env{'form.sortorder'}='desc';
    } else {
       $env{'form.sortorder'}='asc';
    }
       }
       my $sortform = '<span class="LC_nobreak">'
                     .&mt('Sort by:').' '
                     .&Apache::loncommon::select_form($env{'form.sortfield'},
                                                         'sortfield',
                                                         %sort_fields)
                     .' '
                     .&Apache::loncommon::select_form($env{'form.sortorder'},
                                                         'sortorder',
                                                         (asc =>&mt('Ascending'),
                                                          desc=>&mt('Descending')
                                                          ))
                     .'</span>';
       ##
       ## Display links for 'prev' and 'next' pages (if necessary) and Display Options
       $r->print('<fieldset>'."\n"
                .'<legend>'.&mt('Display Options').'</legend>'."\n"
                .$sortform
                .' '
                .&viewoptions()
                .'</fieldset>'
                .&prev_next_buttons($min,$env{'form.show'},$total_results)
       );
   
     if ($total_results == 0) {      if ($total_results == 0) {
         $r->print("There are currently no results.\n".          $r->print('<meta HTTP-EQUIV="Refresh" CONTENT="2" />'.
                   "</form></body></html>");                    '<p class="LC_info">'.&mt('There are currently no results.').'</p>'.
                     "</form>".
     &Apache::loncommon::end_page());
         return;          return;
     } else {      } else {
         $r->print          $r->print('<div>'.
             ("<center>Results $min to $max out of $total_results</center>\n");                    mt('Results [_1] to [_2] out of [_3]',
                        $min,$max,$total_results).
                     "</div>\n");
     }      }
     ##      ##
     ## Get results from MySQL table      ## Get results from MySQL table
     ##      my $sort_command  = 'id>='.$min.' AND id<='.$max;
     my @Results = &Apache::lonmysql::get_rows($table,      my $order;
                                               'id>='.$min.' AND id<='.$max);      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.      ## Loop through the results and output them.
     ##      my $tabletype = 'metadata';
       if ($area eq 'portfolio') {
           $tabletype = 'portfolio_search';
       }
       $r->print(&Apache::loncommon::start_data_table());
     foreach my $row (@Results) {      foreach my $row (@Results) {
         if ($connection->aborted()) {          if ($connection->aborted()) {
             untie %groupsearch_db if (tied(%groupsearch_db));              &cleanup();
             &Apache::lonmysql::disconnect_from_db();  
             return;              return;
         }          }
         my %Fields = %{&parse_row(@$row)};          my %Fields = %{&parse_row($tabletype,@$row)};
         my $output="<p>\n";          my $output;
         my $prefix=&catalogmode_output($Fields{'title'},$Fields{'url'});          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          # Render the result into html
         $output.= &$viewfunction($prefix,%Fields);          $output.= &$viewfunction($prefix,%Fields);
         # Print them out as they come in.          # Print them out as they come in.
         $r->print($output);          $r->print(&Apache::loncommon::start_data_table_row()
                    .'<td>'
                    .$output
                    .'</td>'
                    .&Apache::loncommon::end_data_table_row()
           );
         $r->rflush();          $r->rflush();
     }      }
       $r->print(&Apache::loncommon::end_data_table());
     if (@Results < 1) {      if (@Results < 1) {
         $r->print("There were no results matching your query");          $r->print('<p class="LC_info">'
                    .&mt('There were no results matching your query.')
                    .'</p>');
     } else {      } else {
         $r->print          $r->print(
             ('<center>'.              &prev_next_buttons($min,$env{'form.show'},$total_results,
              &prev_next_buttons($min,$ENV{'form.show'},$total_results,                                  "table=".$env{'form.table'}.
                                 "table=".$ENV{'form.table'}.                                  "&amp;phase=results".
                                 "&phase=results".                                  "&amp;persistent_db_id=".
                                 "&persistent_db_id=".                                  $env{'form.persistent_db_id'})
                                 $ENV{'form.persistent_db_id'})          );
              ."</center>\n"  
              );  
     }      }
     $r->print("</form></body></html>");      $r->print("</form>".&Apache::loncommon::end_page());
     $r->rflush();      $r->rflush();
     untie %groupsearch_db if (tied(%groupsearch_db));      untie %groupsearch_db if (tied(%groupsearch_db));
     return;      return;
Line 2240  sub display_results { Line 3080  sub display_results {
   
 =pod  =pod
   
 =item &catalogmode_output($title,$url)  =item &catalogmode_output($title,$url,$fnum,$checkbox_num)
   
 Returns html needed for the various catalog modes.  Gets inputs from  Returns html needed for the various catalog modes.  Gets inputs from
 $ENV{'form.catalogmode'}.  Stores data in %groupsearch_db and $fnum   $env{'form.catalogmode'}.  Stores data in %groupsearch_db.
 (local variable).  
   
 =cut  =cut
   
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
 {   
 my $fnum = 0;  
   
 sub catalogmode_output {  sub catalogmode_output {
     my $output = '';      my $output = '';
     my ($title,$url) = @_;      my ($title,$url,$fnum,$checkbox_num) = @_;
     if ($ENV{'form.catalogmode'} eq 'interactive') {      if ($env{'form.catalogmode'} eq 'interactive') {
         $title=~ s/\'/\\\'/g;          $title=~ s/\'/\\\'/g;
         if ($ENV{'form.catalogmode'} eq 'interactive') {          if ($env{'form.catalogmode'} eq 'interactive') {
             $output.=<<END               $output.=<<END 
 <font size='-1'><INPUT TYPE="button" NAME="returnvalues" VALUE="SELECT"  <font size='-1'><input type="button" name="returnvalues" value="select"
 onClick="javascript:select_data('$title','$url')">  onclick="javascript:select_data('$title','$url')" />
 </font>  </font>
 END  END
         }          }
     } elsif ($ENV{'form.catalogmode'} eq 'groupsearch') {      } elsif ($env{'form.catalogmode'} eq 'import') {
         $groupsearch_db{"pre_${fnum}_link"}=$url;          $groupsearch_db{"pre_${fnum}_link"}=$url;
         $groupsearch_db{"pre_${fnum}_title"}=$title;          $groupsearch_db{"pre_${fnum}_title"}=$title;
         $output.=<<END;          $output.=<<END;
 <font size='-1'>  <font size='-1'>
 <input type="checkbox" name="returnvalues" value="SELECT"  <input type="checkbox" name="returnvalues" value="select"
 onClick="javascript:queue($fnum)" />  onclick="javascript:queue($checkbox_num,$fnum)" />
 </font>  </font>
 END  END
         $fnum++;  
     }      }
     return $output;      return $output;
 }  }
   
 }  
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
   
 =pod  =pod
   
 =item &parse_row  =item &parse_row()
   
 Parse a row returned from the database.  Parse a row returned from the database.
   
Line 2294  Parse a row returned from the database. Line 3127  Parse a row returned from the database.
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
 sub parse_row {  sub parse_row {
     my @Row = @_;      my ($tabletype,@Row) = @_;
     my %Fields;      my %Fields;
       if (! scalar(@Datatypes)) {
           &set_up_table_structure($tabletype);
       }
     for (my $i=0;$i<=$#Row;$i++) {      for (my $i=0;$i<=$#Row;$i++) {
         $Fields{$DataOrder[$i]}=&Apache::lonnet::unescape($Row[$i]);          $Fields{$Datatypes[$i]->{'name'}}=&unescape($Row[$i]);
     }      }
     $Fields{'language'} =       $Fields{'language'} = 
         &Apache::loncommon::languagedescription($Fields{'lang'});          &Apache::loncommon::languagedescription($Fields{'language'});
     $Fields{'copyrighttag'} =      $Fields{'copyrighttag'} =
         &Apache::loncommon::copyrightdescription($Fields{'copyright'});          &Apache::loncommon::copyrightdescription($Fields{'copyright'});
     $Fields{'mimetag'} =      $Fields{'mimetag'} =
Line 2316  sub parse_row { Line 3152  sub parse_row {
 =item &parse_raw_result()  =item &parse_raw_result()
   
 Takes a line from the file of results and parse it.  Returns a hash   Takes a line from the file of results and parse it.  Returns a hash 
 with keys for the following fields:  with keys according to column labels
 'title', 'author', 'subject', 'url', 'keywords', 'version', 'notes',   
 'abstract', 'mime', 'lang', 'owner', 'copyright', 'creationdate',   
 'lastrevisiondate'.  
   
 In addition, the following tags are set by calling the appropriate   In addition, the following tags are set by calling the appropriate 
 lonnet function: 'language', 'cprtag', 'mimetag'.  lonnet function: 'language', 'copyrighttag', 'mimetag'.
   
 The 'title' field is set to "Untitled" if the title field is blank.  The 'title' field is set to "Untitled" if the title field is blank.
   
Line 2333  The 'title' field is set to "Untitled" i Line 3166  The 'title' field is set to "Untitled" i
 ###########################################################  ###########################################################
 ###########################################################  ###########################################################
 sub parse_raw_result {  sub parse_raw_result {
     my ($result,$hostname) = @_;      my ($result,$hostname,$tabletype) = @_;
     # Check for a comma - if it is there then we do not need to unescape the      # conclude from self to others regarding fields
     # string.  There seems to be some kind of problem with some items in      my %Fields=&LONCAPA::lonmetadata::metadata_col_to_hash
     # the database - the entire string gets sent out unescaped...?          ($tabletype,
     unless ($result =~ /,/) {           map {
         $result = &Apache::lonnet::unescape($result);              &unescape($_);
     }           } (split(/\,/,$result)) );
     my @fields=map {  
         &Apache::lonnet::unescape($_);  
     } (split(/\,/,$result));  
     my ($title,$author,$subject,$url,$keywords,$version,  
         $notes,$abstract,$mime,$lang,  
         $creationdate,$lastrevisiondate,$owner,$copyright)=@fields;  
     my %Fields =   
         ( title     => &Apache::lonnet::unescape($title),  
           author    => &Apache::lonnet::unescape($author),  
           subject   => &Apache::lonnet::unescape($subject),  
           url       => &Apache::lonnet::unescape($url),  
           keywords  => &Apache::lonnet::unescape($keywords),  
           version   => &Apache::lonnet::unescape($version),  
           notes     => &Apache::lonnet::unescape($notes),  
           abstract  => &Apache::lonnet::unescape($abstract),  
           mime      => &Apache::lonnet::unescape($mime),  
           lang      => &Apache::lonnet::unescape($lang),  
           owner     => &Apache::lonnet::unescape($owner),  
           copyright => &Apache::lonnet::unescape($copyright),  
           creationdate     => &Apache::lonnet::unescape($creationdate),  
           lastrevisiondate => &Apache::lonnet::unescape($lastrevisiondate)  
         );  
     $Fields{'language'} =   
         &Apache::loncommon::languagedescription($Fields{'lang'});  
     $Fields{'copyrighttag'} =  
         &Apache::loncommon::copyrightdescription($Fields{'copyright'});  
     $Fields{'mimetag'} =  
         &Apache::loncommon::filedescription($Fields{'mime'});  
     if ($Fields{'author'}=~/^(\s*|error)$/) {  
         $Fields{'author'}="Unknown Author";  
     }  
     # Put spaces in the keyword list, if needed.  
     $Fields{'keywords'}=~ s/,([A-z])/, $1/g;   
     if ($Fields{'title'}=~ /^\s*$/ ) {   
         $Fields{'title'}='Untitled';   
     }  
     unless ($ENV{'user.adv'}) {  
         # What is this anyway?  
         $Fields{'keywords'} = '- not displayed -';  
         $Fields{'notes'}    = '- not displayed -';  
         $Fields{'abstract'} = '- not displayed -';  
         $Fields{'subject'}  = '- not displayed -';  
     }  
     if (length($Fields{'abstract'})>200) {  
         $Fields{'abstract'} =   
             substr($Fields{'abstract'},0,200).'...';  
     }  
     if (length($Fields{'keywords'})>200) {  
         $Fields{'keywords'} =  
             substr($Fields{'keywords'},0,200).'...';  
     }  
     return %Fields;      return %Fields;
 }  }
   
Line 2410  sub handle_custom_fields { Line 3192  sub handle_custom_fields {
     my $customshow='';      my $customshow='';
     my $extrashow='';      my $extrashow='';
     my @customfields;      my @customfields;
     if ($ENV{'form.customshow'}) {      if ($env{'form.customshow'}) {
         $customshow=$ENV{'form.customshow'};          $customshow=$env{'form.customshow'};
         $customshow=~s/[^\w\s]//g;          $customshow=~s/[^\w\s]//g;
         my @fields=map {          my @fields=map {
             "<font color=\"#008000\">$_:</font><!-- $_ -->";              "<font color=\"#008000\">$_:</font><!-- $_ -->";
Line 2427  sub handle_custom_fields { Line 3209  sub handle_custom_fields {
         if ($result=~/^(custom\=.*)$/) { # grab all custom metadata          if ($result=~/^(custom\=.*)$/) { # grab all custom metadata
             my $tmp=$result;              my $tmp=$result;
             $tmp=~s/^custom\=//;              $tmp=~s/^custom\=//;
             my ($k,$v)=map {&Apache::lonnet::unescape($_);              my ($k,$v)=map {&unescape($_);
                         } split(/\,/,$tmp);                          } split(/\,/,$tmp);
             $customhash{$k}=$v;              $customhash{$k}=$v;
         }          }
Line 2440  sub handle_custom_fields { Line 3222  sub handle_custom_fields {
   
 =pod  =pod
   
 =item &search_results_header  =item &search_results_header()
   
 Output the proper html headers and javascript code to deal with different   Output the proper html headers and javascript code to deal with different 
 calling modes.  calling modes.
   
 Takes most inputs directly from %ENV, except $mode.    Takes most inputs directly from %env, except $mode.  
   
 =over 4  =over 4
   
Line 2459  The following environment variables are Line 3241  The following environment variables are
   
 =item 'form.catalogmode'   =item 'form.catalogmode' 
   
 Checked for 'interactive' and 'groupsearch'.  Checked for 'interactive' and 'import'.
   
 =item 'form.mode'  =item 'form.mode'
   
Line 2467  Checked for existance & 'edit' mode. Line 3249  Checked for existance & 'edit' mode.
   
 =item 'form.form'  =item 'form.form'
   
   Contains the name of the form that has the input fields to set
   
 =item 'form.element'  =item 'form.element'
   
   the name of the input field to put the URL into
   
   =item 'form.titleelement'
   
   the name of the input field to put the title into
   
 =back  =back
   
 =cut  =cut
Line 2477  Checked for existance & 'edit' mode. Line 3267  Checked for existance & 'edit' mode.
 ######################################################################  ######################################################################
 sub search_results_header {  sub search_results_header {
     my ($importbutton,$closebutton) = @_;      my ($importbutton,$closebutton) = @_;
     my $result = '';  
       my $js;
     # output beginning of search page      # output beginning of search page
     # conditional output of script functions dependent on the mode in      # conditional output of script functions dependent on the mode in
     # which the search was invoked      # which the search was invoked
     if ($ENV{'form.catalogmode'} eq 'interactive'){      if ($env{'form.catalogmode'} eq 'interactive'){
  if (! exists($ENV{'form.mode'}) || $ENV{'form.mode'} ne 'edit') {   if (! exists($env{'form.mode'}) || $env{'form.mode'} ne 'edit') {
             $result.=<<SCRIPT;              $js.=<<SCRIPT;
 <script type="text/javascript">  <script type="text/javascript">
   // <![CDATA[
     function select_data(title,url) {      function select_data(title,url) {
  changeTitle(title);   changeTitle(title);
  changeURL(url);   changeURL(url);
Line 2500  sub search_results_header { Line 3292  sub search_results_header {
     parent.opener.inf.document.forms.resinfo.elements.u.value=val;      parent.opener.inf.document.forms.resinfo.elements.u.value=val;
  }   }
     }      }
   // ]]>
 </script>  </script>
 SCRIPT  SCRIPT
         } elsif ($ENV{'form.mode'} eq 'edit') {          } elsif ($env{'form.mode'} eq 'edit') {
             my $form = $ENV{'form.form'};              my $form = $env{'form.form'};
             my $element = $ENV{'form.element'};              my $element = $env{'form.element'};
             $result.=<<SCRIPT;              my $titleelement = $env{'form.titleelement'};
       my $changetitle;
       if (!$titleelement) {
    $changetitle='function changeTitle(val) {}';
       } else {
       $changetitle=<<END;
   function changeTitle(val) {
       if (parent.targetwin.document) {
           parent.targetwin.document.forms["$form"].elements["$titleelement"].value=val;
       } else {
    var url = 'forms[\"$form\"].elements[\"$titleelement\"].value';
           alert("Unable to transfer data to "+url);
       }
   }
   END
               }
   
               $js.=<<SCRIPT;
 <script type="text/javascript">  <script type="text/javascript">
   // <![CDATA[
 function select_data(title,url) {  function select_data(title,url) {
     changeURL(url);      changeURL(url);
       changeTitle(title);
     parent.close();      parent.close();
 }  }
 function changeTitle(val) {  $changetitle
 }  
 function changeURL(val) {  function changeURL(val) {
     if (parent.targetwin.document) {      if (parent.targetwin.document) {
         parent.targetwin.document.forms["$form"].elements["$element"].value=val;          parent.targetwin.document.forms["$form"].elements["$element"].value=val;
Line 2521  function changeURL(val) { Line 3332  function changeURL(val) {
         alert("Unable to transfer data to "+url);          alert("Unable to transfer data to "+url);
     }      }
 }  }
   // ]]>
 </script>  </script>
 SCRIPT  SCRIPT
         }          }
     }      }
     $result.=<<SCRIPT if $ENV{'form.catalogmode'} eq 'groupsearch';      my $inhibit_menu = "&".&Apache::loncommon::inhibit_menu_check();
       $js.=<<SCRIPT if $env{'form.catalogmode'} eq 'import';
 <script type="text/javascript">  <script type="text/javascript">
     function queue(val) {  // <![CDATA[
         if (document.forms.results.returnvalues[val].checked) {      function queue(checkbox_num,val) {
             parent.statusframe.document.forms.statusform.elements.Queue.value +='1a'+val+'b';          if (document.forms.results.returnvalues.length != "undefined" &&
               typeof(document.forms.results.returnvalues.length) == "number") {
               if (document.forms.results.returnvalues[checkbox_num].checked) {
                   parent.statusframe.document.forms.statusform.elements.acts.value +='1a'+val+'b';
               } else {
                   parent.statusframe.document.forms.statusform.elements.acts.value +='0a'+val+'b';
               }
         } else {          } else {
             parent.statusframe.document.forms.statusform.elements.Queue.value +='0a'+val+'b';              if (document.forms.results.returnvalues.checked) {
                   parent.statusframe.document.forms.statusform.elements.acts.value +='1a'+val+'b';
               } else {
                   parent.statusframe.document.forms.statusform.elements.acts.value +='0a'+val+'b';
               }
         }          }
     }      }
     function select_group() {      function select_group() {
  parent.window.location=   parent.window.location=
     "/adm/groupsort?mode=$ENV{'form.mode'}&catalogmode=groupsearch&acts="+      "/adm/groupsort?mode=$env{'form.mode'}&amp;catalogmode=import$inhibit_menu&amp;acts="+
     parent.statusframe.document.forms.statusform.elements.Queue.value;      parent.statusframe.document.forms.statusform.elements.acts.value;
     }      }
   // ]]>
 </script>  </script>
 SCRIPT  SCRIPT
     $result.=<<END;  
 </head>      my $start_page  = &Apache::loncommon::start_page(undef,$js,
 <form name="results" method="post" action="" >       {'only_body' =>1});
 <input type="hidden" name="Queue" value="" />      my $result=<<END;
   $start_page
   <form name="results" method="post" action="/adm/searchcat">
 $importbutton  $importbutton
 END  END
     return $result;      return $result;
 }  }
   
 ######################################################################  
 ######################################################################  
 sub search_status_header {  
     return <<ENDSTATUS;  
 <html><head><title>Search Status</title></head>  
 <body>  
 <h3>Search Status</h3>  
 Sending search request to LON-CAPA servers.<br />  
 ENDSTATUS  
 }  
   
 sub results_link {  sub results_link {
     my $basic_link   = "/adm/searchcat?"."&table=".$ENV{'form.table'}.      my $basic_link   = "/adm/searchcat?"."&amp;table=".$env{'form.table'}.
         "&persistent_db_id=".$ENV{'form.persistent_db_id'};          "&amp;persistent_db_id=".$env{'form.persistent_db_id'};
     my $results_link = $basic_link."&phase=results".      my $results_link = $basic_link."&amp;phase=results".
         "&pause=1"."&start=1";          "&amp;pause=1"."&amp;start=1";
     return $results_link;      return $results_link;
 }  }
   
Line 2573  sub results_link { Line 3388  sub results_link {
 ######################################################################  ######################################################################
 sub print_frames_interface {  sub print_frames_interface {
     my $r = shift;      my $r = shift;
     my $basic_link = "/adm/searchcat?"."&table=".$ENV{'form.table'}.      my $basic_link = "/adm/searchcat?"."&amp;table=".$env{'form.table'}.
         "&persistent_db_id=".$ENV{'form.persistent_db_id'};          "&amp;persistent_db_id=".$env{'form.persistent_db_id'};
     my $run_search_link = $basic_link."&phase=run_search";      my $run_search_link = $basic_link."&amp;phase=run_search";
     my $results_link = &results_link();      my $results_link = &results_link();
     my $result = <<"ENDFRAMES";      my $js = <<JS;
 <html>  <script type="text/javascript">
 <head>  // <![CDATA[
 <script>  
 var targetwin = opener;  var targetwin = opener;
   var queue = '';
   // ]]>
 </script>  </script>
 <title>LON-CAPA Digital Library Search Results</title>  JS
 </head>  
 <frameset rows="150,*">      my $start_page =
           &Apache::loncommon::start_page('LON-CAPA Digital Library Search Results',
          $js,
          {'frameset'    => 1,
    'add_entries' => {
       'rows' => "150,*",},});
       my $end_page =
           &Apache::loncommon::end_page({'frameset' => 1});
   
       my $result = <<"ENDFRAMES";
   $start_page
     <frame name="statusframe"  src="$run_search_link">      <frame name="statusframe"  src="$run_search_link">
     <frame name="resultsframe" src="$results_link">      <frame name="resultsframe" src="$results_link">
 </frameset>  $end_page
 </html>  
 ENDFRAMES  ENDFRAMES
   
     $r->print($result);      $r->print($result);
Line 2599  ENDFRAMES Line 3424  ENDFRAMES
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
   
   sub has_stat_data {
       my ($values) = @_;
       if ( (defined($values->{'count'})      && $values->{'count'}      ne '') ||
            (defined($values->{'stdno'})      && $values->{'stdno'}      ne '') ||
            (defined($values->{'disc'})       && $values->{'disc'}       ne '') ||
            (defined($values->{'avetries'})   && $values->{'avetries'}   ne '') ||
            (defined($values->{'difficulty'}) && $values->{'difficulty'} ne '')) {
           return 1;
       }
       return 0;
   }
   
   sub statfields {
       return ('count','stdno','disc','avetries','difficulty');
   }
   
   sub has_eval_data {
       my ($values) = @_;
       if ( (defined($values->{'clear'})     && $values->{'clear'}     ne '') ||
            (defined($values->{'technical'}) && $values->{'technical'} ne '') ||
            (defined($values->{'correct'})   && $values->{'correct'}   ne '') ||
            (defined($values->{'helpful'})   && $values->{'helpful'}   ne '') ||
            (defined($values->{'depth'})     && $values->{'depth'}     ne '')) {
           return 1;
       }
       return 0;
   }
   
   sub evalfields { 
       return ('clear','technical','correct','helpful','depth');
   }
   
   ######################################################################
   ######################################################################
   
 =pod   =pod 
   
 =item Metadata Viewing Functions  =item Metadata Viewing Functions
   
 Output is a HTML-ified string.  Output is a HTML-ified string.
   
 Input arguments are title, author, subject, url, keywords, version,  Input arguments are title, author, subject, url, keywords, version,
 notes, short abstract, mime, language, creation date,  notes, short abstract, mime, language, creation date,
 last revision date, owner, copyright, hostname, and  last revision date, owner, copyright, hostname, and
Line 2619  extra custom metadata to show. Line 3480  extra custom metadata to show.
 ######################################################################  ######################################################################
 sub detailed_citation_view {  sub detailed_citation_view {
     my ($prefix,%values) = @_;      my ($prefix,%values) = @_;
     my $result=<<END;      my $result;
 <b>$prefix<a href="http://$ENV{'HTTP_HOST'}$values{'url'}"       my $jumpurl=$values{'url'};
     target='search_preview'>$values{'title'}</a></b>      $jumpurl=~s|^/ext/|http://|;
 <p>      $result .= '<b>'.$prefix.
 <b>$values{'author'}</b>, <i>$values{'owner'}</i><br />          '<img src="'.&Apache::loncommon::icon($values{'url'}).'" alt="" />'.'&nbsp;'.
           '<a href="'.$jumpurl.'?inhibitmenu=yes" '.
 <b>Subject:       </b> $values{'subject'}<br />          'target="preview">'.$values{'title'}."</a></b>\n";
 <b>Keyword(s):    </b> $values{'keywords'}<br />      $result .= "<p>\n";
 <b>Notes:         </b> $values{'notes'}<br />      $result .= '<b>'.$values{'author'}.'</b>,'.
 <b>MIME Type:     </b> $values{'mimetag'}<br />          ' <i>'.$values{'owner'}.'</i><br />';
 <b>Language:      </b> $values{'language'}<br />      foreach my $field 
 <b>Copyright/Distribution:</b> $values{'cprtag'}<br />          (
 </p>           { name=>'url',
 $values{'extrashow'}             translate => '<b>URL:</b>&nbsp;[_1]',
 <p>             special => 'url link',},
 $values{'shortabstract'}           { name=>'subject',
 </p>             translate => '<b>Subject:</b>&nbsp;[_1]',},
 <hr align='left' width='200' noshade />           { name=>'keywords',
 END             translate => '<b>Keywords:</b>&nbsp;[_1]',},
            { name=>'notes',
              translate => '<b>Notes:</b>&nbsp;[_1]',},
            { name=>'mimetag',
              translate => '<b>MIME Type:</b>&nbsp;[_1]',},
            { name=>'standards',
              translate => '<b>Standards:</b>[_1]',},
            { name=>'copyrighttag',
              translate => '<b>Copyright/Distribution:</b>&nbsp;[_1]',},
            { name=>'count',
              format => "%d",
              translate => '<b>Access Count:</b>&nbsp;[_1]',},
            { name=>'stdno',
              format => "%d",
              translate => '<b>Number of Students:</b>&nbsp;[_1]',},
            { name=>'avetries',
              format => "%.2f",
              translate => '<b>Average Tries:</b>&nbsp;[_1]',},
            { name=>'disc',
              format => "%.2f",
              translate => '<b>Degree of Discrimination:</b>&nbsp;[_1]',},
            { name=>'difficulty',
              format => "%.2f",
              translate => '<b>Degree of Difficulty:</b>&nbsp;[_1]',},
            { name=>'clear',
              format => "%.2f",
              translate => '<b>Clear:</b>&nbsp;[_1]',},
            { name=>'depth',
              format => "%.2f",
              translate => '<b>Depth:</b>&nbsp;[_1]',},
            { name=>'helpful',
              format => "%.2f",
              translate => '<b>Helpful:</b>&nbsp;[_1]',},
            { name=>'correct',
              format => "%.2f",
              translate => '<b>Correct:</b>&nbsp;[_1]',},
            { name=>'technical',
              format => "%.2f",
              translate => '<b>Technical:</b>&nbsp;[_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 .= '<b>'.&mt($field->{'translate'}).'</b>';
               foreach my $item (split(',',$values{$field->{'name'}})){
                   $item = &Apache::lonnet::clutter($item);
                   $result .= '<br />'.&display_url($item,1).'<br />';
               }
           } elsif (exists($field->{'format'}) && $field->{'format'} ne ''){
               $result.= &mt($field->{'translate'},
                             sprintf($field->{'format'},
                                     $values{$field->{'name'}}))."<br />\n";
           } else {
               if ($field->{'special'} eq 'url link') {
                   $result .= '<br />'.&display_url($jumpurl,1).'<br />';
               } else {
                   $result.= &mt($field->{'translate'},
                                 $values{$field->{'name'}});
               }
               $result .= "<br />\n";
           }
       }
       $result .= "</p>";
       if (exists($values{'extrashow'}) && $values{'extrashow'} ne '') {
           $result .= '<p>'.$values{'extrashow'}.'</p>';
       }
       if (exists($values{'shortabstract'}) && $values{'shortabstract'} ne '') {
           $result .= '<p>'.$values{'shortabstract'}.'</p>';
       }
     return $result;      return $result;
 }  }
   
   sub detailed_citation_preview {
       my ($prefix,%values)=@_;
       return &detailed_citation_view($prefix,%values).
              '</td><td>'.
              &Apache::lonindexer::showpreview($values{'url'});
   }
   
   
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
   
Line 2653  END Line 3599  END
 ######################################################################  ######################################################################
 sub summary_view {  sub summary_view {
     my ($prefix,%values) = @_;      my ($prefix,%values) = @_;
     my $result=<<END;      my $icon=&Apache::loncommon::icon($values{'url'});
 $prefix<a href="http://$ENV{'HTTP_HOST'}$values{'url'}"       my $result=qq{$prefix<img src="$icon" alt="" />};
    target='search_preview'>$values{'author'}</a><br />      if (exists($env{'form.sortfield'}) && 
 $values{'title'}<br />          $env{'form.sortfield'} !~ /^(default|
 $values{'owner'} -- $values{'lastrevisiondate'}<br />                                       author|
                                        url|
                                        title|
                                        owner|
                                        lastrevisiondate|
                                        copyright)$/x) {
           my $tmp = $values{$env{'form.sortfield'}};
           if (! defined($tmp)) { $tmp = 'undefined'; }
           $result .= '&nbsp;'.$tmp.'&nbsp;';
       }
       my $jumpurl=$values{'url'};
       $jumpurl=~s|^/ext/|http://|;
       my $link = '<br />'.&display_url($jumpurl,1).'<br />';
   
       $result.=<<END;
   <a href="$jumpurl?inhibitmenu=yes" 
      target="preview">$values{'title'}</a><br />
   $link<br />
   $values{'author'}, $values{'owner'} -- $values{'lastrevisiondate'}<br />
 $values{'copyrighttag'}<br />  $values{'copyrighttag'}<br />
 $values{'extrashow'}  $values{'extrashow'}
 </p>  
 <hr align='left' width='200' noshade />  
 END  END
     return $result;      return $result;
 }  }
   
   sub summary_preview {
       my ($prefix,%values)=@_;
       return &summary_view($prefix,%values).
              '</td><td>'.
              &Apache::lonindexer::showpreview($values{'url'});
   }
   
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
   
Line 2679  END Line 3648  END
 ######################################################################  ######################################################################
 sub compact_view {  sub compact_view {
     my ($prefix,%values) = @_;      my ($prefix,%values) = @_;
     my $result=<<END;      my $jumpurl=$values{'url'};
 $prefix <a href="http://$ENV{'HTTP_HOST'}$values{'url'}"  target='search_preview'>      $jumpurl=~s|^/ext/|http://|;
 $values{'title'}</a>  
 <b>$values{'author'}</b><br />      my $link = &display_url($jumpurl,1);
 END      
       my $result = 
           $prefix.'<img src="'.&Apache::loncommon::icon($values{'url'}).'" alt="" />';
       if (exists($env{'form.sortfield'}) && 
           $env{'form.sortfield'} !~ /^(default|author|url|title)$/) {
           my $tmp = $values{$env{'form.sortfield'}};
           if (! defined($tmp)) { $tmp = 'undefined'; }
           $result .= '&nbsp;'.$tmp.'&nbsp;';
       }
       $jumpurl = &HTML::Entities::encode($jumpurl,'<>&"');
       $result.=' <span class="LC_nobreak">'.
    '<a href="'.$jumpurl.'?inhibitmenu=yes" target="preview">'.
           &HTML::Entities::encode($values{'title'},'<>&"').'</a></span> '.
    $link.' <b>'.$values{'author'}.'</b> ('.$values{'domain'}.')';
     return $result;      return $result;
 }  }
   
   sub display_url {
       my ($url,$skiplast) = @_;
       my $link;
       if ($url=~m|^/ext/|) {
    $url=~s|^/ext/|http://|;
    $link='<span class="LC_filename">'.$url.'</span>';
       } elsif ($url=~m{^(http://|/uploaded/)}) {
    $link='<span class="LC_filename">'.$url.'</span>';
       } else {
           $link=&Apache::lonhtmlcommon::crumbs(
                     $url,
                     'preview',
                     '',
                     (($env{'form.catalogmode'} eq 'import')?'parent.statusframe.document.forms.statusform':''),
                     $skiplast).' ';
       }
       return $link;
   }
   
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
Line 2701  END Line 3701  END
 ######################################################################  ######################################################################
 sub fielded_format_view {  sub fielded_format_view {
     my ($prefix,%values) = @_;      my ($prefix,%values) = @_;
       my $icon=&Apache::loncommon::icon($values{'url'});
       my %Translated = &Apache::lonmeta::fieldnames();
       my $jumpurl=$values{'url'};
       $jumpurl=~s|^/ext/|http://|;
   
     my $result=<<END;      my $result=<<END;
 $prefix  $prefix <img src="$icon" alt="" />
 <b>URL: </b> <a href="http://$ENV{'HTTP_HOST'}$values{'url'}"   <dl>
               target='search_preview'>$values{'url'}</a>  <dt>URL:</dt>
 <br />      <dd><a href="$jumpurl?inhibitmenu=yes" 
 <b>Title:</b> $values{'title'}<br />           target='preview'>$values{'url'}</a></dd>
 <b>Author(s):</b> $values{'author'}<br />  END
 <b>Subject:</b> $values{'subject'}<br />      foreach my $field ('title','author','domain','subject','keywords','notes',
 <b>Keyword(s):</b> $values{'keywords'}<br />                         'mimetag','language','creationdate','lastrevisiondate',
 <b>Notes:</b> $values{'notes'}<br />                         'owner','copyrighttag','hostname','abstract') {
 <b>MIME Type:</b> $values{'mimetag'}<br />          $result .= (' 'x4).'<dt>'.$Translated{$field}.'</dt>'."\n".
 <b>Language:</b> $values{'language'}<br />              (' 'x8).'<dd>'.$values{$field}.'</dd>'."\n";
 <b>Creation Date:</b> $values{'creationdate'}<br />      }
 <b>Last Revision Date:</b> $values{'lastrevisiondate'}<br />      if (&has_stat_data(\%values)) {
 <b>Publisher/Owner:</b> $values{'owner'}<br />          foreach my $field (&statfields()) {
 <b>Copyright/Distribution:</b> $values{'copyrighttag'}<br />              $result .= (' 'x4).'<dt>'.$Translated{$field}.'</dt>'."\n".
 <b>Repository Location:</b> $values{'hostname'}<br />                  (' 'x8).'<dd>'.$values{$field}.'</dd>'."\n";
 <b>Abstract:</b> $values{'shortabstract'}<br />          }
 $values{'extrashow'}      }
 </p>      if (&has_eval_data(\%values)) {
 <hr align='left' width='200' noshade />          foreach my $field (&evalfields()) {
 END              $result .= (' 'x4).'<dt>'.$Translated{$field}.'</dt>'."\n".
                   (' 'x8).'<dd>'.$values{$field}.'</dd>'."\n";
           }
       }
       $result .= "</dl>\n";
       $result .= $values{'extrashow'};
     return $result;      return $result;
 }  }
   
Line 2741  END Line 3751  END
 ######################################################################  ######################################################################
 sub xml_sgml_view {  sub xml_sgml_view {
     my ($prefix,%values) = @_;      my ($prefix,%values) = @_;
       my $xml = '<LonCapaResource>'."\n";
       # The usual suspects
       foreach my $field ('url','title','author','subject','keywords','notes','domain') {
           $xml .= qq{<$field>$values{$field}</$field>}."\n";
       }
       #
       $xml .= "<mimeInfo>\n";
       foreach my $field ('mime','mimetag') {
           $xml .= qq{<$field>$values{$field}</$field>}."\n";
       }
       $xml .= "</mimeInfo>\n";
       #
       $xml .= "<languageInfo>\n";
       foreach my $field ('language','languagetag') {
           $xml .= qq{<$field>$values{$field}</$field>}."\n";
       }
       $xml .= "</languageInfo>\n";
       #
       foreach my $field ('creationdate','lastrevisiondate','owner') {
           $xml .= qq{<$field>$values{$field}</$field>}."\n";
       }
       #
       $xml .= "<copyrightInfo>\n";
       foreach my $field ('copyright','copyrighttag') {
           $xml .= qq{<$field>$values{$field}</$field>}."\n";
       }
       $xml .= "</copyrightInfo>\n";
       $xml .= qq{<repositoryLocation>$values{'hostname'}</repositoryLocation>}.
           "\n";
       $xml .= qq{<shortabstract>$values{'shortabstract'}</shortabstract>}."\n";
       #
       if (&has_stat_data(\%values)){
           $xml .= "<problemstatistics>\n";
           foreach my $field (&statfields()) {
               $xml .= qq{<$field>$values{$field}</$field>}."\n";            
           }
           $xml .= "</problemstatistics>\n";
       }
       #
       if (&has_eval_data(\%values)) {
           $xml .= "<evaluation>\n";
           foreach my $field (&evalfields) {
               $xml .= qq{<$field>$values{$field}</$field>}."\n";            
           }
           $xml .= "</evaluation>\n";
       }    
       #
       $xml .= "</LonCapaResource>\n";
       $xml = &HTML::Entities::encode($xml,'<>&');
     my $result=<<END;      my $result=<<END;
 $prefix  $prefix
 <pre>  <pre>
 &lt;LonCapaResource&gt;  $xml
 &lt;url&gt;$values{'url'}&lt;/url&gt;  
 &lt;title&gt;$values{'title'}&lt;/title&gt;  
 &lt;author&gt;$values{'author'}&lt;/author&gt;  
 &lt;subject&gt;$values{'subject'}&lt;/subject&gt;  
 &lt;keywords&gt;$values{'keywords'}&lt;/keywords&gt;  
 &lt;notes&gt;$values{'notes'}&lt;/notes&gt;  
 &lt;mimeInfo&gt;  
 &lt;mime&gt;$values{'mime'}&lt;/mime&gt;  
 &lt;mimetag&gt;$values{'mimetag'}&lt;/mimetag&gt;  
 &lt;/mimeInfo&gt;  
 &lt;languageInfo&gt;  
 &lt;language&gt;$values{'lang'}&lt;/language&gt;  
 &lt;languagetag&gt;$values{'language'}&lt;/languagetag&gt;  
 &lt;/languageInfo&gt;  
 &lt;creationdate&gt;$values{'creationdate'}&lt;/creationdate&gt;  
 &lt;lastrevisiondate&gt;$values{'lastrevisiondate'}&lt;/lastrevisiondate&gt;  
 &lt;owner&gt;$values{'owner'}&lt;/owner&gt;  
 &lt;copyrightInfo&gt;  
 &lt;copyright&gt;$values{'copyright'}&lt;/copyright&gt;  
 &lt;copyrighttag&gt;$values{'copyrighttag'}&lt;/copyrighttag&gt;  
 &lt;/copyrightInfo&gt;  
 &lt;repositoryLocation&gt;$values{'hostname'}&lt;/repositoryLocation&gt;  
 &lt;shortabstract&gt;$values{'shortabstract'}&lt;/shortabstract&gt;  
 &lt;/LonCapaResource&gt;  
 </pre>  </pre>
 $values{'extrashow'}  $values{'extrashow'}
 <hr align='left' width='200' noshade />  
 END  END
     return $result;      return $result;
 }  }
Line 2790  END Line 3824  END
 sub filled {  sub filled {
     my ($field)=@_;      my ($field)=@_;
     if ($field=~/\S/ && $field ne 'any') {      if ($field=~/\S/ && $field ne 'any') {
  return 1;          return 1;
       } else {
           return 0;
     }      }
     else {  }
  return 0;  
   ######################################################################
   ######################################################################
   
   =pod 
   
   =item &output_unparsed_phrase_error()
   
   =cut
   
   ######################################################################
   ######################################################################
   sub output_unparsed_phrase_error {
       my ($r,$closebutton,$parms,$hidden_fields,$field)=@_;
       my $errorstring;
       if ($field eq 'basicexp') {
           $errorstring = &mt('Unable to understand the search phrase [_1]. Please modify your search.'
                              ,'<i>'.$env{'form.basicexp'}.'</i>');
       } else {
           $errorstring = &mt('Unable to understand the search phrase [_1]: [_2]'
                              ,'<i>'.$field.'</i>'
                              ,$env{'form.'.$field});
     }      }
       my $heading = &mt('Unparsed Field');
       my $revise  = &mt('Revise search request');
       # make query information persistent to allow for subsequent revision
       my $start_page = &Apache::loncommon::start_page('Search');
       my $end_page   = &Apache::loncommon::end_page();
       $r->print(<<ENDPAGE);
   $start_page
   <form method="post" action="/adm/searchcat">
   $hidden_fields
   $closebutton
   <hr />
   <h2>$heading</h2>
   <p class="LC_warning">
   $errorstring
   </p>
   <p>
   <a href="/adm/searchcat?$parms&amp;persistent_db_id=$env{'form.persistent_db_id'}">$revise</a>
   </p>
   $end_page
   ENDPAGE
 }  }
   
 ######################################################################  ######################################################################
Line 2818  $parms is extra information to include i Line 3895  $parms is extra information to include i
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
 sub output_blank_field_error {  sub output_blank_field_error {
     my ($r,$closebutton,$parms)=@_;      my ($r,$closebutton,$parms,$hidden_fields)=@_;
     # make query information persistent to allow for subsequent revision      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.');
     $r->print(<<BEGINNING);      my $revise = &mt('Revise Search Request');
 <html>      my $heading = &mt('Unactionable Search Query');
 <head>      my $start_page = &Apache::loncommon::start_page('Search');
 <title>The LearningOnline Network with CAPA</title>      my $end_page   = &Apache::loncommon::end_page();
 BEGINNING      if ($closebutton) {
     $r->print(<<RESULTS);          $closebutton = '<p>'.$closebutton.'</p><hr />';
 </head>      } else {
 <body bgcolor="#ffffff">          &Apache::lonhtmlcommon::add_breadcrumb
 <img align='right' src='/adm/lonIcons/lonlogos.gif' />              ({href=>'',
 <h1>Search Catalog</h1>                text=>$heading,});
           $start_page .= &Apache::lonhtmlcommon::breadcrumbs();
       }
   
       $r->print(<<ENDPAGE);
   $start_page
 <form method="post" action="/adm/searchcat">  <form method="post" action="/adm/searchcat">
 $hidden_fields  $hidden_fields
 <a href="/adm/searchcat?$parms&persistent_db_id=$ENV{'form.persistent_db_id'}"  
 >Revise search request</a>&nbsp;  
 $closebutton  $closebutton
 <hr />  </form>
 <h3>Unactionable search query.</h3>  <h2>$heading</h2>
   <p class="LC_warning">
   $errormsg
   </p>
 <p>  <p>
 You did not fill in enough information for the search to be started.  <a href="/adm/searchcat?$parms&amp;persistent_db_id=$env{'form.persistent_db_id'}">$revise</a>
 You need to fill in relevant fields on the search page in order   
 for a query to be processed.  
 </p>  </p>
 </body>  $end_page
 </html>  ENDPAGE
 RESULTS      return;
 }  }
   
 ######################################################################  ######################################################################
Line 2867  Inputs: Line 3948  Inputs:
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
 sub output_date_error {  sub output_date_error {
     my ($r,$message,$closebutton)=@_;      my ($r,$message,$closebutton,$hidden_fields)=@_;
     # make query information persistent to allow for subsequent revision      # make query information persistent to allow for subsequent revision
       my $start_page = &Apache::loncommon::start_page('Search');
       my $end_page   = &Apache::loncommon::end_page();
       my $heading = &mt('Error');
     $r->print(<<RESULTS);      $r->print(<<RESULTS);
 <html>  $start_page
 <head>  
 <title>The LearningOnline Network with CAPA</title>  
 </head>  
 <body bgcolor="#ffffff">  
 <img align='right' src='/adm/lonIcons/lonlogos.gif' />  
 <h1>Search Catalog</h1>  
 <form method="post" action="/adm/searchcat">  <form method="post" action="/adm/searchcat">
 $hidden_fields  $hidden_fields
 <input type='button' value='Revise search request'  <input type='button' value='Revise search request'
 onClick='this.form.submit();' />  onclick='this.form.submit();' />
 $closebutton  $closebutton
   </form>
 <hr />  <hr />
 <h3>Error</h3>  <h3>$heading</h3>
 <p>  <p class="LC_error">
 $message  $message
 </p>  </p>
 </body>  $end_page
 </html>  
 RESULTS  RESULTS
 }  }
   
Line 2920  sub start_fresh_session { Line 3998  sub start_fresh_session {
   
 1;  1;
   
   sub cleanup {
       if (tied(%groupsearch_db)) {
           unless (untie(%groupsearch_db)) {
     &Apache::lonnet::logthis('Failed cleanup searchcat: groupsearch_db');
           }
       }
       &untiehash();
       &Apache::lonmysql::disconnect_from_db();
       return OK;
   }
   
 __END__  __END__
   
 =pod  =pod

Removed from v.1.153  
changed lines
  Added in v.1.320


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>