--- loncom/interface/lonsearchcat.pm 2001/03/20 17:49:03 1.44 +++ loncom/interface/lonsearchcat.pm 2002/07/30 20:26:05 1.149 @@ -1,164 +1,530 @@ -# The LearningOnline Network +# The LearningOnline Network with CAPA # Search Catalog # -# 03/08/2001 Scott Harrison -# Scott Harrison: 03/12/2001, 03/13/2001, 03/14/2001, 03/15/2001, 03/19/2001 -# Scott Harrison: 03/20/2001 +# $Id: lonsearchcat.pm,v 1.149 2002/07/30 20:26:05 matthew Exp $ # -# Functions +# Copyright Michigan State University Board of Trustees # -# handler(server reference) : interacts with the Apache server layer -# (for /adm/searchcat URLs) -# simpletextfield(name,value) : returns HTML formatted string for simple text -# field -# simplecheckbox(name,value) : returns HTML formatted string for simple -# checkbox -# searchphrasefield(title,name,value) : returns HTML formatted string for -# a search expression phrase field -# dateboxes(name, defaultmonth, defaultday, defaultyear) : returns HTML -# formatted string -# for a calendar date -# selectbox(title,name,value,%HASH=options) : returns HTML formatted string for -# a selection box field -# advancedsearch(server reference, environment reference) : perform a complex -# multi-field logical query -# filled(field) : determines whether a given field has been filled -# basicsearch(server reference, environment reference) : perform a simple -# single-field logical query -# output_blank_field_error(server reference) : outputs a message saying that -# more fields need to be filled in -# output_results(output mode, -# server reference, -# environment reference, -# reply list reference) : outputs results from search -# build_SQL_query(field name, logic) : builds a SQL query string from a -# logical expression with AND/OR keywords -# recursive_SQL_query_build(field name, reverse notation expression) : -# builds a SQL query string from a reverse notation expression -# logical expression with AND/OR keywords +# This file is part of the LearningOnline Network with CAPA (LON-CAPA). +# +# LON-CAPA is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# LON-CAPA is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with LON-CAPA; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# /home/httpd/html/adm/gpl.txt +# +# http://www.lon-capa.org/ +# +# YEAR=2001 +# 3/8, 3/12, 3/13, 3/14, 3/15, 3/19 Scott Harrison +# 3/20, 3/21, 3/22, 3/26, 3/27, 4/2, 8/15, 8/24, 8/25 Scott Harrison +# 10/12,10/14,10/15,10/16,11/28,11/29,12/10,12/12,12/16 Scott Harrison +# YEAR=2002 +# 1/17 Scott Harrison +# 6/17 Matthew Hall +# +############################################################################### +############################################################################### + +=pod + +=head1 NAME + +lonsearchcat - LONCAPA Search Interface + +=head1 SYNOPSIS + +Search interface to LON-CAPAs digital library + +=head1 DESCRIPTION + +This module enables searching for a distributed browseable catalog. + +This is part of the LearningOnline Network with CAPA project +described at http://www.lon-capa.org. + +lonsearchcat presents the user with an interface to search the LON-CAPA +digital library. lonsearchcat also initiates the execution of a search +by sending the search parameters to LON-CAPA servers. The progress of +search (on a server basis) is displayed to the user in a seperate window. + +=head1 Internals + +=over 4 + +=cut + +############################################################################### +############################################################################### + +############################################################################### +## ## +## 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; +# ------------------------------------------------- modules used by this module use strict; use Apache::Constants qw(:common); use Apache::lonnet(); use Apache::File(); use CGI qw(:standard); use Text::Query; +use DBI; +use GDBM_File; +use Apache::loncommon(); +use Apache::lonmysql(); -my %language; -my $scrout; -my %metadatafields; -my %cprtag; -my %mimetag; +# ---------------------------------------- variables used throughout the module -sub handler { - my $r = shift; +###################################################################### +###################################################################### -# -------------------------------------- see if called from an interactive mode - map { - my ($name, $value) = split(/=/,$_); - $value =~ tr/+/ /; - $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg; - if ($name eq 'catalogmode') { - $ENV{'form.'.$name}=$value; - } - } (split(/&/,$ENV{'QUERY_STRING'})); +=pod - $r->content_type('text/html'); - $r->send_http_header; - return OK if $r->header_only; +=item Global variables - %metadatafields=(); +=over 4 - my $hidden=''; - $hidden=< -END +=item $importbutton -# ------------------------------------------------ First, check out environment - $metadatafields{'owner'}=$ENV{'user.name'}.'@'.$ENV{'user.domain'}; +button to take the select results and go to group sorting -# --------------------------------- Compute various listings of metadata values - - %language=(); - $language{'any'}='Any language'; - { - my $fh=Apache::File->new($r->dir_config('lonTabDir').'/language.tab'); - map { - $_=~/(\w+)\s+([\w\s\-]+)/; - $language{$1}=$2; - } <$fh>; - } +=item %groupsearch_db - %cprtag=(); - $cprtag{'any'}='Any copyright/distribution'; - { - my $fh=Apache::File->new($r->dir_config('lonIncludes').'/copyright.tab'); - map { - $_=~/(\w+)\s+([\w\s\-]+)/; - $cprtag{$1}=$2; - } <$fh>; - } +Database hash used to save values for the groupsearch RAT interface. - %mimetag=(); - $mimetag{'any'}='Any type'; - { - my $fh=Apache::File->new($r->dir_config('lonTabDir').'/filetypes.tab'); - map { - $_=~/(\w+)\s+(\w+)\s+([\w\s\-]+)/; - $mimetag{$1}=".$1 $3"; - } <$fh>; - } +=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 +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 ); +my %persistent_db; +my $hidden_fields; +###################################################################### +###################################################################### + +=pod + +=item &handler() - main handler invoked by httpd child + +=item Variables + +=over 4 + +=item $hidden + +holds 'hidden' html forms + +=item $scrout + +string that holds portions of the screen output - if ($ENV{'form.basicsubmit'} eq 'SEARCH') { - return &basicsearch($r,\%ENV); +=back + +=cut + +###################################################################### +###################################################################### +sub handler { + my $r = shift; + # + my $closebutton; # button that closes the search window + # This button is different for the RAT compared to + # normal invocation. + # + $r->content_type('text/html'); + $r->send_http_header; + return OK if $r->header_only; + ## + ## Pick up form fields passed in the links. + ## + &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, + ['catalogmode','launch','acts','mode','form','element','pause', + 'phase','persistent_db_id','table','start','show']); + ## + ## The following is a trick - we wait a few seconds if asked to so + ## the daemon running the search can get ahead of the daemon + ## printing the results. We only need (theoretically) to do + ## this once, so the pause indicator is deleted + ## + if (exists($ENV{'form.pause'})) { + sleep(3); + delete($ENV{'form.pause'}); + } + ## + ## Initialize global variables + ## + my $domain = $r->dir_config('lonDefDomain'); + $diropendb= "/home/httpd/perl/tmp/".&Apache::lonnet::escape($domain). + "\_".&Apache::lonnet::escape($ENV{'user.name'})."_searchcat.db"; + # + # set the name of the persistent database + # $ENV{'form.persistent_db_id'} can only have digits in it. + if (! exists($ENV{'form.persistent_db_id'}) || + ($ENV{'form.persistent_db_id'} =~ /\D/) || + ($ENV{'form.launch'} eq '1')) { + $ENV{'form.persistent_db_id'} = time; + } + my $persistent_db_file = "/home/httpd/perl/tmp/". + &Apache::lonnet::escape($domain). + '_'.&Apache::lonnet::escape($ENV{'user.name'}). + '_'.$ENV{'form.persistent_db_id'}.'_persistent_search.db'; + ## + if (! &get_persistent_form_data($r,$persistent_db_file)) { + &write_status($r,"Unable to get persistent data"); } - elsif ($ENV{'form.advancedsubmit'} eq 'SEARCH') { - return &advancedsearch($r,\%ENV); + ## + ## Clear out old values from groupsearch database + ## + untie %groupsearch_db if (tied(%groupsearch_db)); + if ($ENV{'form.launch'} eq '1') { + if (tie(%groupsearch_db,'GDBM_File',$diropendb,&GDBM_WRCREAT(),0640)) { + &start_fresh_session(); + untie %groupsearch_db; + } else { + $r->print('Unable to tie hash to db '. + 'file'); + return OK; + } + } + ## + ## Configure dynamic components of interface + ## + $hidden_fields = ''; + ## + if ($ENV{'form.catalogmode'} eq 'interactive') { + $closebutton=""."\n"; + } elsif ($ENV{'form.catalogmode'} eq 'groupsearch') { + $closebutton=< +END + $importbutton=< +END + } else { + $closebutton = ''; + $importbutton = ''; + } + ## + ## Sanity checks on form elements + ## + if (!defined($ENV{'form.viewselect'})) { + $ENV{'form.viewselect'} ="Detailed Citation View"; + } + $ENV{'form.phase'} = 'disp_basic' if (! exists($ENV{'form.phase'})); + ## + ## Switch on the phase + ## + if ($ENV{'form.phase'} eq 'disp_basic') { + &print_basic_search_form($r,$closebutton); + } elsif ($ENV{'form.phase'} eq 'disp_adv') { + &print_advanced_search_form($r,$closebutton); + } elsif ($ENV{'form.phase'} eq 'results') { + &display_results($r,$importbutton,$closebutton); + } elsif($ENV{'form.phase'} eq 'run_search') { + my ($query,$customquery,$customshow,$libraries,$pretty_string) = + &get_persistent_data($persistent_db_file, + ['query','customquery','customshow', + 'libraries','pretty_string']); + &write_status($r,"query = $query"); + &write_status($r,"customquery = $customquery"); + &write_status($r,"customshow = $customshow"); + &write_status($r,"libraries = $libraries"); + &write_status($r,"pretty_string = $pretty_string"); + &run_search($r,$query,$customquery,$customshow, + $libraries,$pretty_string); + } elsif(($ENV{'form.phase'} eq 'basic_search') || + ($ENV{'form.phase'} eq 'adv_search')) { + # Set up table + if (! defined(&create_results_table())) { + $r->print(<Search Error + +Unable to create table in which to store search results. +The search has been aborted. + + +END + return OK; + } + delete($ENV{'form.launch'}); + if (! &make_form_data_persistent($r,$persistent_db_file)) { + $r->print(<Search Error + +Unable to properly store search information. The search has been aborted. + + +END + return OK; + } + # + # We are running a search + my ($query,$customquery,$customshow,$libraries) = + (undef,undef,undef,undef); + my $pretty_string; + if ($ENV{'form.phase'} eq 'basic_search') { + ($query,$pretty_string) = &parse_basic_search($r,$closebutton); + } else { # Advanced search + ($query,$customquery,$customshow,$libraries,$pretty_string) + = &parse_advanced_search($r,$closebutton); + return OK if (! defined($query)); + } + &make_persistent($r, + { query => $query, + customquery => $customquery, + customshow => $customshow, + libraries => $libraries, + pretty_string => $pretty_string }, + $persistent_db_file); + ## + ## Print out the frames interface + ## + &print_frames_interface($r); } + return OK; +} + +###################################################################### +###################################################################### + +=pod + +=item &print_basic_search_form() - $scrout=''; # building a part of screen output - $scrout.=&searchphrasefield('Limit by title','title', - $ENV{'form.title'}); +Returns a scalar which holds html for the basic search form. - $scrout.=&searchphrasefield('Limit by author','author', - $ENV{'form.author'}); +=cut - $scrout.=&searchphrasefield('Limit by subject','subject', - $ENV{'form.subject'}); +###################################################################### +###################################################################### - $scrout.=&searchphrasefield('Limit by keywords','keywords', - $ENV{'form.keywords'}); +sub print_basic_search_form{ + my ($r,$closebutton) = @_; + my $scrout=<<"ENDDOCUMENT"; + + +The LearningOnline Network with CAPA + + + + +

Search Catalog

+
+ +$hidden_fields +

Basic Search

+

+Enter terms or phrases separated by AND, OR, or NOT +then press SEARCH below. +

+

+ + + +
+ENDDOCUMENT + $scrout.=' '.&simpletextfield('basicexp',$ENV{'form.basicexp'},40). + ' '; +# $scrout.=&simplecheckbox('allversions',$ENV{'form.allversions'}); +# $scrout.='Search historic archives'; + my $checkbox = &simplecheckbox('related',$ENV{'form.related'}); + $scrout.=<Advanced Search
$checkbox use related words
+

+

  +$closebutton +END + $scrout.=&selectbox(undef,'viewselect', + $ENV{'form.viewselect'}, + undef,undef,undef, + sort(keys(%Views))); + $scrout.=< +

+
+ + +ENDDOCUMENT + $r->print($scrout); + return; +} +###################################################################### +###################################################################### - $scrout.=&searchphrasefield('Limit by URL','url', - $ENV{'form.url'}); +=pod - $scrout.=&searchphrasefield('Limit by version','version', - $ENV{'form.version'}); +=item &advanced_search_form() - $scrout.=&searchphrasefield('Limit by notes','notes', - $ENV{'form.notes'}); +Returns a scalar which holds html for the advanced search form. - $scrout.=&searchphrasefield('Limit by abstract','abstract', - $ENV{'form.abstract'}); +=cut - $ENV{'form.mime'}='notxxx' unless length($ENV{'form.mime'}); - $scrout.=&selectbox('Limit by MIME type','mime', - $ENV{'form.mime'},%mimetag); +###################################################################### +###################################################################### +sub print_advanced_search_form{ + my ($r,$closebutton) = @_; + my $advanced_buttons = <<"END"; +

+ + +$closebutton + +

+END + if (!defined($ENV{'form.viewselect'})) { + $ENV{'form.viewselect'} ="Detailed Citation View"; + } + my $scrout=<<"ENDHEADER"; + + +The LearningOnline Network with CAPA + + + + +

Advanced Catalog Search

+
+Enter terms or phrases separated by search operators +such as AND, OR, or NOT.
+
+$advanced_buttons +$hidden_fields + + + +\n"; + $scrout.=&searchphrasefield_with_related('title', 'title' , + $ENV{'form.title'}); + $scrout.=&searchphrasefield('author', 'author' ,$ENV{'form.author'}); + $scrout.=&searchphrasefield_with_related('subject', 'subject' , + $ENV{'form.subject'}); + $scrout.=&searchphrasefield_with_related('keywords','keywords', + $ENV{'form.keywords'}); + $scrout.=&searchphrasefield('URL', 'url' ,$ENV{'form.url'}); + $scrout.=&searchphrasefield_with_related('notes', 'notes' , + $ENV{'form.notes'}); + $scrout.=&searchphrasefield_with_related('abstract','abstract', + $ENV{'form.abstract'}); + # Hack - an empty table row. + $scrout.="\n"; + $scrout.=&searchphrasefield('file
extension','mime', + $ENV{'form.mime'}); + $scrout.="\n"; + $scrout.=&searchphrasefield('publisher
owner','owner', + $ENV{'form.owner'}); + $scrout.="
VIEW: +ENDHEADER + $scrout.=&selectbox(undef,'viewselect', + $ENV{'form.viewselect'}, + undef,undef,undef, + sort(keys(%Views))); + $scrout.="Related
Words
   
   
\n"; + $ENV{'form.category'}='any' unless length($ENV{'form.category'}); + $scrout.=&selectbox('File Category','category', + $ENV{'form.category'}, + 'any','Any category', + undef, + (&Apache::loncommon::filecategories())); $ENV{'form.language'}='any' unless length($ENV{'form.language'}); - + #---------------------------------------------------------------- + # Allow restriction to multiple domains. + # I make the crazy assumption that there will never be a domain 'any'. + # + $ENV{'form.domains'} = 'any' if (! exists($ENV{'form.domains'})); + my @allowed_domains = (ref($ENV{'form.domains'}) ? @{$ENV{'form.domains'}} + : ($ENV{'form.domains'}) ); + my %domain_hash = (); + foreach (@allowed_domains) { + $domain_hash{$_}++; + } + my @domains =&Apache::loncommon::get_domains(); + # adjust the size of the select box + my $size = 4; + my $size = (scalar @domains < ($size - 1) ? scalar @domains + 1 : $size); + $scrout.="\n".''. + 'DOMAINS
'. + '\n"; + #---------------------------------------------------------------- $scrout.=&selectbox('Limit by language','language', - $ENV{'form.language'},%language); - - + $ENV{'form.language'},'any','Any Language', + \&{Apache::loncommon::languagedescription}, + (&Apache::loncommon::languageids), + ); # ------------------------------------------------ Compute date selection boxes $scrout.=< LIMIT BY CREATION DATE RANGE: -
+
between: CREATIONDATESTART $scrout.=&dateboxes('creationdatestart',1,1,1976, @@ -166,21 +532,18 @@ CREATIONDATESTART $ENV{'form.creationdatestart_day'}, $ENV{'form.creationdatestart_year'}, ); - $scrout.=< LIMIT BY LAST REVISION DATE RANGE: -
between: +
between: LASTREVISIONDATESTART $scrout.=&dateboxes('lastrevisiondatestart',1,1,1976, $ENV{'form.lastrevisiondatestart_month'}, @@ -196,264 +559,543 @@ LASTREVISIONDATEEND $ENV{'form.lastrevisiondateend_year'}, ); $scrout.='

'; - - $scrout.=&searchphrasefield('Limit by publisher/owner','owner', - $ENV{'form.owner'}); -# $metadatafields{'owner'}); - $ENV{'form.copyright'}='any' unless length($ENV{'form.copyright'}); $scrout.=&selectbox('Limit by copyright/distribution','copyright', - $ENV{'form.copyright'},%cprtag); - + $ENV{'form.copyright'}, + 'any','Any copyright/distribution', + \&{Apache::loncommon::copyrightdescription}, + (&Apache::loncommon::copyrightids), + ); # ------------------------------------------- Compute customized metadata field $scrout.=< -LIMIT BY OTHER METADATA FIELDS: +LIMIT BY SPECIAL METADATA FIELDS: -For author-specific metadata, enter in an expression in the form of -key=value separated by operators such as AND or OR.
+For resource-specific metadata, enter in an expression in the form of +key=value separated by operators such as AND, OR or NOT.
Example: grandmother=75 OR grandfather=85 -
+
CUSTOMMETADATA -$scrout.=&simpletextfield('custommetadata',$ENV{'form.custommetadata'}); -$scrout.=' initial users of this system do not need to worry about this option'; - -# ---------------------------------------------------------------- Print screen - $r->print(< - -The LearningOnline Network with CAPA - - - -

Search Catalog

- -$hidden -
-

Basic Search

+ $scrout.=&simpletextfield('custommetadata',$ENV{'form.custommetadata'}); + $scrout.=< -Enter terms or phrases separated by search operators -such as AND or OR then press SEARCH below. Terms should be specific -to the title, author, subject, notes, or abstract information associated -with a resource. -
-ENDDOCUMENT - $r->print(&simpletextfield('basicexp',$ENV{'form.basicexp'})); - $r->print(' '); - $r->print(&simplecheckbox('titleonly',$ENV{'form.titleonly'})); - $r->print('Title only '); - $r->print(&simplecheckbox('allversions',$ENV{'form.allversions'})); - $r->print(<Search historic archives
-
- - - -

-
-

Advanced Search

-$scrout -

- - - -

+SHOW SPECIAL METADATA FIELDS: + +Enter in a space-separated list of special metadata fields to show +in a fielded listing for each record result. +
+CUSTOMSHOW + $scrout.=&simpletextfield('customshow',$ENV{'form.customshow'}); + $scrout.=< ENDDOCUMENT - return OK; -} + $r->print($scrout); + return; +} + +###################################################################### +###################################################################### + +=pod + +=item &get_persistent_form_data + +Inputs: filename of database + +Outputs: returns undef on database errors. + +This function is the reverse of &make_persistent() for form data. +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 +overwritten. Form values that are array references may have values appended +to them. + +=cut + +###################################################################### +###################################################################### +sub get_persistent_form_data { + my $r = shift; + my $filename = shift; + return 0 if (! -e $filename); + return undef if (! tie(%persistent_db,'GDBM_File',$filename, + &GDBM_READER(),0640)); + # + # These make sure we do not get array references printed out as 'values'. + my %arrays_allowed = ('form.category'=>1,'form.domains'=>1); + # + # Loop through the keys, looking for 'form.' + foreach my $name (keys(%persistent_db)) { + next if ($name !~ /^form./); + my @values = map { + &Apache::lonnet::unescape($_); + } split(',',$persistent_db{$name}); + next if (@values <1); + if (exists($ENV{$name})) { + if (ref($ENV{$name}) eq 'ARRAY') { + # If it is an array, tack @values on the end of it. + $ENV{$name} = [@$ENV{$name},@values]; + } elsif (! ref($ENV{$name}) && $arrays_allowed{$name}) { + # if arrays are allowed, turn it into one and add @values + $ENV{$name} = [$ENV{$name},@values]; + } # otherwise, assume the value in $ENV{$name} is better than ours. + } else { + if ($arrays_allowed{$name}) { + $ENV{$name} = [@values]; + } else { + $ENV{$name} = $values[0] if ($values[0]); + } + } + } + untie (%persistent_db); + return 1; +} +###################################################################### +###################################################################### + +=pod + +=item &get_persistent_data + +Inputs: filename of database, ref to array of values to recover. + +Outputs: array of values. Returns undef on error. + +This function is the reverse of &make_persistent(); +Retrieve persistent data from %persistent_db. Retrieved items will have their +values unescaped. If the item contains commas (before unescaping), the +returned value will be an array pointer. + +=cut + +###################################################################### +###################################################################### +sub get_persistent_data { + my $filename = shift; + my @Vars = @{shift()}; + my @Values; # Return array + return undef if (! -e $filename); + return undef if (! tie(%persistent_db,'GDBM_File',$filename, + &GDBM_READER(),0640)); + foreach my $name (@Vars) { + if (! exists($persistent_db{$name})) { + push @Values, undef; + next; + } + my @values = map { + &Apache::lonnet::unescape($_); + } split(',',$persistent_db{$name}); + if (@values == 1) { + push @Values,$values[0]; + } else { + push @Values,\@values; + } + } + untie (%persistent_db); + return @Values; +} + +###################################################################### +###################################################################### + +=pod + +=item &make_persistent() + +Inputs: Hash of values to save, filename of persistent database. + +Store variables away to the %persistent_db. +Values will be escaped. Values that are array pointers will have their +elements escaped and concatenated in a comma seperated string. + +=cut + +###################################################################### +###################################################################### +sub make_persistent { + my $r = shift; + my %save = %{shift()}; + my $filename = shift; + return undef if (! tie(%persistent_db,'GDBM_File', + $filename,&GDBM_WRCREAT(),0640)); + foreach my $name (keys(%save)) { + next if (! exists($save{$name})); + next if (! defined($save{$name}) || $save{$name} eq ''); + my @values = (ref($save{$name}) ? @{$save{$name}} : ($save{$name})); + # We handle array references, but not recursively. + my $store = join(',', map { &Apache::lonnet::escape($_); } @values ); + $persistent_db{$name} = $store; + } + untie(%persistent_db); + return 1; +} + +###################################################################### +###################################################################### + +=pod + +=item &make_form_data_persistent() + +Inputs: filename of persistent database. + +Store most form variables away to the %persistent_db. +Values will be escaped. Values that are array pointers will have their +elements escaped and concatenated in a comma seperated string. + +=cut + +###################################################################### +###################################################################### +sub make_form_data_persistent { + my $r = shift; + my $filename = shift; + my %save; + foreach (keys(%ENV)) { + next if (! /^form/ || /submit/); + $save{$_} = $ENV{$_}; + } + return &make_persistent($r,\%save,$filename); +} + +###################################################################### +# HTML form building functions # +###################################################################### + +=pod + +=item HTML form building functions + +=over 4 + +=cut -# --------------------------------------------------------- Various form fields +############################################### +############################################### + +=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)=@_; - return ''; + my ($name,$value,$size)=@_; + $size = 20 if (! defined($size)); + return ''; } +############################################### +############################################### + +=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 ''; + $checked="checked" if $value eq 'on'; + return ''; +} + +############################################### +############################################### + +=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 ''.$title. + ': '; } +############################################### +############################################### + +=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)=@_; - my $instruction=<$uctitle:". - " $instruction
". - ''; + return ''.&fieldtitle($title).''. + &simpletextfield($name,$value,50)." \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 ''.&fieldtitle($title).''. + &simpletextfield($name,$value,50).' '. + &simplecheckbox($name.'_related',$ENV{'form.'.$name.'_related'}). + " \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)=('','',''); - my $month=< - - - - - - - - - - - - - - -END - $month=~s/(\"$currentmonth\")/$1 SELECTED/ if length($currentmonth); + # + # Day my $day=< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - END + for (my $i = 1; $i<=31; $i++) { + $day.="\n"; + } + $day.="\n"; $day=~s/(\"$currentday\")/$1 SELECTED/ if length($currentday); + # + # Month + my $month=< + +END + my $i = 1; + foreach (qw/January February March April May June + July August September October November December /){ + $month .="\n"; + $i++; + } + $month.="\n"; + $month=~s/(\"$currentmonth\")/$1 SELECTED/ if length($currentmonth); + # + # Year (obviously) my $year=< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - END + my $maxyear = 2051; + for (my $i = 1976; $i<=$maxyear; $i++) { + $year.="\n"; + } + $year.="\n"; $year=~s/(\"$currentyear\")/$1 SELECTED/ if length($currentyear); return "$month$day$year"; } +############################################### +############################################### + +=pod + +=item &selectbox() + +Returns a scalar containing an html tag. + +=item $default + +The default value of the form. Can be $anyvalue, or in @idlist. + +=item $anyvalue + +The