--- loncom/interface/lonsearchcat.pm 2004/07/19 16:38:07 1.231 +++ loncom/interface/lonsearchcat.pm 2025/03/18 18:57:28 1.361 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Search Catalog # -# $Id: lonsearchcat.pm,v 1.231 2004/07/19 16:38:07 raeburn Exp $ +# $Id: lonsearchcat.pm,v 1.361 2025/03/18 18:57:28 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -52,8 +52,6 @@ search (on a server basis) is displayed =head1 Internals -=over 4 - =cut ############################################################################### @@ -63,7 +61,7 @@ package Apache::lonsearchcat; use strict; use Apache::Constants qw(:common :http); -use Apache::lonnet(); +use Apache::lonnet; use Apache::File(); use CGI qw(:standard); use Text::Query; @@ -77,6 +75,10 @@ use LONCAPA::lonmetadata(); use HTML::Entities(); use Parse::RecDescent; use Apache::lonnavmaps; +use Apache::lonindexer(); +use Apache::lonwishlist(); +use LONCAPA; +use Time::HiRes qw(sleep); ###################################################################### ###################################################################### @@ -93,7 +95,9 @@ my %persistent_db; # gdbm hash which h # The different view modes and associated functions my %Views = ("detailed" => \&detailed_citation_view, + "detailedpreview" => \&detailed_citation_preview, "summary" => \&summary_view, + "summarypreview" => \&summary_preview, "fielded" => \&fielded_format_view, "xml" => \&xml_sgml_view, "compact" => \&compact_view); @@ -113,12 +117,7 @@ sub handler { 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 $bodytag; # LON-CAPA standard body tag, gotten from - # &Apache::lonnet::bodytag. - # No title, no table, just a <body> tag. - my $loaderror=&Apache::lonnet::overloaderror($r); - if ($loaderror) { return $loaderror; } # my $closebutton; # button that closes the search window # This button is different for the RAT compared to @@ -137,74 +136,83 @@ sub handler { &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, ['catalogmode','launch','acts','mode','form','element','pause', 'phase','persistent_db_id','table','start','show', - 'cleargroupsort','titleelement']); + 'cleargroupsort','titleelement','area','inhibitmenu']); ## ## The following is a trick - we wait a few seconds if asked to so ## the daemon running the search can get ahead of the daemon ## printing the results. We only need (theoretically) to do ## this once, so the pause indicator is deleted ## - if (exists($ENV{'form.pause'})) { - sleep(1); - delete($ENV{'form.pause'}); + if (exists($env{'form.pause'})) { + sleep(0.1); + delete($env{'form.pause'}); } ## ## Initialize global variables ## my $domain = $r->dir_config('lonDefDomain'); - $diropendb= "/home/httpd/perl/tmp/". - "$ENV{'user.domain'}_$ENV{'user.name'}_searchcat.db"; + my $temp_file_dir = LONCAPA::tempdir(); + $diropendb= $temp_file_dir . + "$env{'user.domain'}_$env{'user.name'}_sel_res.db"; # # set the name of the persistent database - # $ENV{'form.persistent_db_id'} can only have digits in it. - if (! exists($ENV{'form.persistent_db_id'}) || - ($ENV{'form.persistent_db_id'} =~ /\D/) || - ($ENV{'form.launch'} eq '1')) { - $ENV{'form.persistent_db_id'} = time; - } - $bodytag=&Apache::loncommon::bodytag(undef,undef,undef,1); - 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'; + # $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 = $temp_file_dir . + &escape($domain). + '_'.&escape($env{'user.name'}). + '_'.$env{'form.persistent_db_id'}.'_persistent_search.db'; ## &Apache::lonhtmlcommon::clear_breadcrumbs(); - if (exists($ENV{'request.course.id'}) && $ENV{'request.course.id'} ne '') { - &Apache::lonhtmlcommon::add_breadcrumb - ({href=>'/adm/searchcat?'. - 'catalogmode='.$ENV{'form.catalogmode'}. - '&launch='.$ENV{'form.launch'}. - '&mode='.$ENV{'form.mode'}, - text=>"Course and Catalog Search", - target=>'_top', - bug=>'Searching',}); - } else { - &Apache::lonhtmlcommon::add_breadcrumb - ({href=>'/adm/searchcat?'. - 'catalogmode='.$ENV{'form.catalogmode'}. - '&launch='.$ENV{'form.launch'}. - '&mode='.$ENV{'form.mode'}, - text=>"Catalog Search", - target=>'_top', - bug=>'Searching',}); + + my @allowed_searches = ('portfolio'); + if (&Apache::lonnet::allowed('bre',$env{'request.role.domain'}) eq 'F') { + push(@allowed_searches,'res'); + } + my $crumb_text = 'Portfolio Search'; + if (@allowed_searches ==2) { + $crumb_text = 'Portfolio and Content Library Search'; + } + my $target = '_top'; + if ((($env{'request.lti.login'}) && ($env{'request.lti.target'} eq 'iframe')) || + (($env{'request.deeplink.login'}) && ($env{'request.deeplink.target'} eq '_self'))) { + if ($env{'form.phase'} =~ /^(sort|run_search)$/) { + $target = '_parent'; + } else { + $target = '_self'; + } } + &Apache::lonhtmlcommon::add_breadcrumb + ({href=>'/adm/searchcat?'. + &Apache::loncommon::inhibit_menu_check(). + '&catalogmode='.$env{'form.catalogmode'}. + '&launch='.$env{'form.launch'}. + '&mode='.$env{'form.mode'}, + text=>"$crumb_text", + target=>$target, + bug=>'Searching',}); # - if ($ENV{'form.phase'} !~ m/(basic|adv|course)_search/) { + if ($env{'form.phase'} !~ m/(basic|adv|course)_search/) { if (! &get_persistent_form_data($persistent_db_file)) { - if ($ENV{'form.phase'} =~ /(run_search|results)/) { + if ($env{'form.phase'} =~ /(run_search|results)/) { &Apache::lonnet::logthis('lonsearchcat:'. 'Unable to recover data from '. $persistent_db_file); - $r->print(<<END); -<html> -<head><title>LON-CAPA Search Error</title></head> -$bodytag -We were unable to retrieve data describing your search. This is a serious -error and has been logged. Please alert your LON-CAPA administrator. -</body> -</html> -END - return OK; + my $msg = + &mt('We were unable to retrieve data describing your search.'). + ' '.&mt('This is a serious error and has been logged.'). + '<br />'. + &mt('Please alert your LON-CAPA administrator.'); + &Apache::loncommon::simple_error_page( + $r,'Search Error', + $msg, + {'no_auto_mt_msg' => 1}); + return OK; } } } else { @@ -214,18 +222,19 @@ END ## Clear out old values from groupsearch database ## untie %groupsearch_db if (tied(%groupsearch_db)); - if (($ENV{'form.cleargroupsort'} eq '1') || - (($ENV{'form.launch'} eq '1') && - ($ENV{'form.catalogmode'} eq 'groupsearch'))) { + if (($env{'form.cleargroupsort'} eq '1') || + (($env{'form.launch'} eq '1') && + ($env{'form.catalogmode'} eq 'import'))) { if (tie(%groupsearch_db,'GDBM_File',$diropendb,&GDBM_WRCREAT(),0640)) { &start_fresh_session(); untie %groupsearch_db; - delete($ENV{'form.cleargroupsort'}); + delete($env{'form.cleargroupsort'}); } else { # This is a stupid error to give to the user. # It really tells them nothing. - $r->print('<html><head></head>'.$bodytag. - 'Unable to tie hash to db file</body></html>'); + my $msg = 'Unable to tie hash to db file.'; + &Apache::loncommon::simple_error_page($r,'Search Error', + $msg); return OK; } } @@ -233,44 +242,51 @@ END ## Configure hidden fields ## $hidden_fields = '<input type="hidden" name="persistent_db_id" value="'. - $ENV{'form.persistent_db_id'}.'" />'."\n"; - if (exists($ENV{'form.catalogmode'})) { + $env{'form.persistent_db_id'}.'" />'."\n"; + if (exists($env{'form.catalogmode'})) { $hidden_fields .= &hidden_field('catalogmode'); } - if (exists($ENV{'form.form'})) { + if (exists($env{'form.form'})) { $hidden_fields .= &hidden_field('form'); } - if (exists($ENV{'form.element'})) { + if (exists($env{'form.element'})) { $hidden_fields .= &hidden_field('element'); } - if (exists($ENV{'form.titleelement'})) { + if (exists($env{'form.titleelement'})) { $hidden_fields .= &hidden_field('titleelement'); } - if (exists($ENV{'form.mode'})) { + if (exists($env{'form.mode'})) { $hidden_fields .= &hidden_field('mode'); } + 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 ## - if ($ENV{'form.catalogmode'} eq 'interactive') { - $closebutton="<input type='button' name='close' value='CLOSE' "; - if ($ENV{'form.phase'} =~ /(results|run_search)/) { - $closebutton .="onClick='parent.close()'"; + if ($env{'form.catalogmode'} eq 'interactive') { + $closebutton="<input type='button' name='close' value='".&mt('Close')."' "; + if ($env{'form.phase'} =~ /(results|run_search)/) { + $closebutton .="onclick='parent.close()'"; } else { - $closebutton .="onClick='self.close()'"; + $closebutton .="onclick='self.close()'"; } - $closebutton .=">\n"; - } elsif ($ENV{'form.catalogmode'} eq 'groupsearch') { - $closebutton="<input type='button' name='close' value='CLOSE' "; - if ($ENV{'form.phase'} =~ /(results|run_search)/) { - $closebutton .="onClick='parent.close()'"; + $closebutton .=" />\n"; + } elsif ($env{'form.catalogmode'} eq 'import') { + $closebutton="<input type='button' name='close' value='".&mt('Close')."' "; + if ($env{'form.phase'} =~ /(results|run_search)/) { + $closebutton .="onclick='parent.close()'"; } else { - $closebutton .="onClick='self.close()'"; + $closebutton .="onclick='self.close()'"; } - $closebutton .= ">"; + $closebutton .= " />"; + my $txt_import = &mt('IMPORT'); $importbutton=<<END; -<input type='button' name='import' value='IMPORT' -onClick='javascript:select_group()'> +<input type='button' name='import' value='$txt_import' +onclick='javascript:select_group()' /> END } else { $closebutton = ''; @@ -279,79 +295,68 @@ END ## ## Sanity checks on form elements ## - if (!defined($ENV{'form.viewselect'})) { - if (($ENV{'form.catalogmode'} eq 'groupsearch') || - ($ENV{'form.catalogmode'} eq 'interactive')) { - $ENV{'form.viewselect'} ="Compact View"; - } else { - $ENV{'form.viewselect'} ="Detailed Citation View"; - } + if (!defined($env{'form.viewselect'})) { + $env{'form.viewselect'} ="summary"; } - $ENV{'form.phase'} = 'disp_basic' if (! exists($ENV{'form.phase'})); - $ENV{'form.show'} = 20 if (! exists($ENV{'form.show'})); + $env{'form.phase'} = 'disp_basic' if (! exists($env{'form.phase'})); + $env{'form.show'} = 20 if (! exists($env{'form.show'})); # - $ENV{'form.searchmode'} = 'basic' if (! exists($ENV{'form.searchmode'})); - if ($ENV{'form.phase'} eq 'adv_search' || - $ENV{'form.phase'} eq 'disp_adv') { - $ENV{'form.searchmode'} = 'advanced'; - } elsif ($ENV{'form.phase'} eq 'course_search') { - $ENV{'form.searchmode'} = 'course_search'; - } - # - if ($ENV{'form.searchmode'} eq 'advanced') { - &Apache::lonhtmlcommon::add_breadcrumb - ({href=>'/adm/searchcat?phase=disp_adv&'. - 'catalogmode='.$ENV{'form.catalogmode'}. - '&launch='.$ENV{'form.launch'}. - '&mode='.$ENV{'form.mode'}, - text=>"Advanced Search", - bug=>'Searching',}); - } elsif ($ENV{'form.searchmode'} eq 'course search') { + $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'; + } + # + if ($env{'form.searchmode'} eq 'advanced') { + my $srchtype = 'Content Library'; + if ($env{'form.area'} eq 'portfolio') { + $srchtype = 'Portfolio'; + } &Apache::lonhtmlcommon::add_breadcrumb - ({href=>'/adm/searchcat?phase=disp_adv&'. - 'catalogmode='.$ENV{'form.catalogmode'}. - '&launch='.$ENV{'form.launch'}. - '&mode='.$ENV{'form.mode'}, - text=>"Course Search", + ({href=>'/adm/searchcat?'.&Apache::loncommon::inhibit_menu_check(). + '&phase=disp_adv'. + '&catalogmode='.$env{'form.catalogmode'}. + '&launch='.$env{'form.launch'}. + '&mode='.$env{'form.mode'}, + text=>"Advanced $srchtype Search", bug=>'Searching',}); - } + } ## ## Switch on the phase ## - if ($ENV{'form.phase'} eq 'disp_basic') { + if ($env{'form.phase'} eq 'disp_basic') { &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,$hidden_fields); - } elsif ($ENV{'form.phase'} eq 'results') { - &display_results($r,$importbutton,$closebutton,$diropendb); - } elsif ($ENV{'form.phase'} =~ /^(sort|run_search)$/) { - my ($query,$customquery,$customshow,$libraries,$pretty_string) = + } elsif ($env{'form.phase'} eq 'results') { + &display_results($r,$importbutton,$closebutton,$diropendb, + $env{'form.area'}); + } elsif ($env{'form.phase'} =~ /^(sort|run_search)$/) { + my ($query,$customquery,$customshow,$libraries,$pretty_string,$domainsref) = &get_persistent_data($persistent_db_file, ['query','customquery','customshow', - 'libraries','pretty_string']); - if ($ENV{'form.phase'} eq 'sort') { - &print_sort_form($r,$pretty_string); - } elsif ($ENV{'form.phase'} eq 'run_search') { + 'libraries','pretty_string','domains']); + if ($env{'form.phase'} eq 'sort') { + &print_sort_form($r,$pretty_string,$target); + } elsif ($env{'form.phase'} eq 'run_search') { &run_search($r,$query,$customquery,$customshow, - $libraries,$pretty_string); + $libraries,$pretty_string,$env{'form.area'},$domainsref,$target); } - } elsif ($ENV{'form.phase'} eq 'course_search') { - &course_search($r); - } elsif(($ENV{'form.phase'} eq 'basic_search') || - ($ENV{'form.phase'} eq 'adv_search')) { + } elsif(($env{'form.phase'} eq 'basic_search') || + ($env{'form.phase'} eq 'adv_search')) { # # We are running a search, try to parse it - my ($query,$customquery,$customshow,$libraries) = - (undef,undef,undef,undef); + my ($query,$customquery,$customshow,$libraries,$domains) = + (undef,undef,undef,undef,undef); my $pretty_string; - if ($ENV{'form.phase'} eq 'basic_search') { - ($query,$pretty_string,$libraries) = + if ($env{'form.phase'} eq 'basic_search') { + ($query,$pretty_string,$libraries,$domains) = &parse_basic_search($r,$closebutton,$hidden_fields); return OK if (! defined($query)); - &make_persistent({ basicexp => $ENV{'form.basicexp'}}, + &make_persistent({ basicexp => $env{'form.basicexp'}}, $persistent_db_file); } else { # Advanced search - ($query,$customquery,$customshow,$libraries,$pretty_string) + ($query,$customquery,$customshow,$libraries,$pretty_string,$domains) = &parse_advanced_search($r,$closebutton,$hidden_fields); return OK if (! defined($query)); } @@ -359,36 +364,33 @@ END customquery => $customquery, customshow => $customshow, libraries => $libraries, - pretty_string => $pretty_string }, + pretty_string => $pretty_string, + domains => $domains }, $persistent_db_file); # # Set up table - if (! defined(&create_results_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); - $r->print(<<END); -<html><head><title>Search Error</title></head> -$bodytag -Unable to create table in which to store search results. -The search has been aborted. -</body> -</html> -END - return OK; + + 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'}); + delete($env{'form.launch'}); if (! &make_form_data_persistent($r,$persistent_db_file)) { - $r->print(<<END); -<html><head><title>Search Error</title></head> -$bodytag -Unable to properly store search information. The search has been aborted. -</body> -</html> -END - return OK; - } + 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 ## @@ -397,7 +399,7 @@ END } } return OK; -} +} # # The mechanism used to store values away and retrieve them does not @@ -406,23 +408,23 @@ END # 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 ($env{'form.phase'} eq 'basic_search') { + if (! exists($env{'form.related'})) { + $env{'form.related'} = ''; } - if (! exists($ENV{'form.domains'})) { - $ENV{'form.domains'} = ''; + if (! exists($env{'form.domains'})) { + $env{'form.domains'} = ''; } - } elsif ($ENV{'form.phase'} eq 'adv_search') { + } 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'} = ''; + 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'} = ''; + } elsif ($env{'form.phase'} eq 'course_search') { + if (! exists($env{'form.crsrelated'})) { + $env{'form.crsrelated'} = ''; } } } @@ -430,217 +432,17 @@ sub clean_up_environment { sub hidden_field { my ($name,$value) = @_; if (! defined($value)) { - $value = $ENV{'form.'.$name}; + $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 course_search { - my $r=shift; - my $bodytag=&Apache::loncommon::bodytag('Course Search'); - my $pretty_search_string = '<b>'.$ENV{'form.courseexp'}.'</b>'; - my $search_string = $ENV{'form.courseexp'}; - my @New_Words; - 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; - $r->print('<html><head><title>LON-CAPA Course Search</title></head>'. - $bodytag.'<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 - undef %alreadyseen; - %alreadyseen=(); - my $c=$r->connection; - if (tie(%hash,'GDBM_File',$ENV{'request.course.fn'}.".db", - &GDBM_READER(),0640)) { - foreach (keys %hash) { - if ($c->aborted()) { last; } - if (($_=~/^src\_(.+)$/) && (!$alreadyseen{$hash{$_}})) { - &checkonthis($r,$hash{$_},0,$hash{'title_'.$1},$fulltext, - @allwords); - } - } - untie(%hash); - } - unless ($totalfound) { - $r->print('<p>'.&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(); - my @allres=$navmap->retrieveResources(); - my %discussiontime = &Apache::lonnet::dump('discussiontimes', - $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}, - $ENV{'course.'.$ENV{'request.course.id'}.'.num'}); - foreach my $resource (@allres) { - my $result = ''; - my $applies = 0; - my $symb = $resource->symb(); - my $ressymb = $symb; - if ($symb =~ m#(___adm/\w+/\w+)/(\d+)/bulletinboard$#) { - $ressymb = 'bulletin___'.$2.$1.'/'.$2.'/bulletinboard'; - unless ($ressymb =~ m#bulletin___\d+___adm/wrapper#) { - $ressymb=~s#(bulletin___\d+___)#$1adm/wrapper/#; - } - } - if (defined($discussiontime{$ressymb})) { - my %contrib = &Apache::lonnet::restore($ressymb,$ENV{'request.course.id'}, - $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}, - $ENV{'course.'.$ENV{'request.course.id'}.'.num'}); - if ($contrib{'version'}) { - for (my $id=1;$id<=$contrib{'version'};$id++) { - unless (($contrib{'hidden'}=~/\.$id\./) || ($contrib{'deleted'}=~/\.$id\./)) { - if ($contrib{$id.':subject'}) { - $result .= $contrib{$id.':subject'}; - } - if ($contrib{$id.':message'}) { - $result .= $contrib{$id.':message'}; - } - if ($contrib{$id,':attachmenturl'}) { - if ($contrib{$id,':attachmenturl'} =~ m-/([^/]+)$-) { - $result .= $1; - } - } - $applies = &checkwords($result,$applies,@allwords); - } - } - } - } -# Does this discussion apply? - if ($applies) { - my ($map,$ind,$url)=&Apache::lonnet::decode_symb($ressymb); - my $disctype = &mt('resource'); - if ($url =~ m#/bulletinboard$#) { - if ($url =~m#^adm/wrapper/adm/.*/bulletinboard$#) { - $url =~s#^adm/wrapper##; - } - $disctype = &mt('bulletin board'); - } else { - $url = '/res/'.$url; - } - if ($url =~ /\?/) { - $url .= '&symb='; - } else { - $url .= '?symb='; - } - $url .= &Apache::lonnet::escape($resource->symb()); - my $title = $resource->compTitle(); - $r->print('<br /><a href="'.$url.'" target="cat">'. - ($title?$title:$url).'</a> - '.$disctype.'<br />'); - $totaldiscussions++; - } else { - $r->print(' .'); - } - } - unless ($totaldiscussions) { - $r->print('<p>'.&mt('No matches found in postings').'.</p>'); - } - } - -# =================================================== Done going through course - $r->print('</body></html>'); -} - -# =============================== This pulls up a resource and its dependencies -sub checkonthis { - my ($r,$url,$level,$title,$fulltext,@allwords)=@_; - $alreadyseen{$url}=1; - $r->rflush(); - my $result=&Apache::lonnet::metadata($url,'title').' '. - &Apache::lonnet::metadata($url,'subject').' '. - &Apache::lonnet::metadata($url,'abstract').' '. - &Apache::lonnet::metadata($url,'keywords'); - if (($url) && ($fulltext)) { - $result.=&Apache::lonnet::ssi_body($url); - } - $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(' '); - } - $r->print('<a href="'.$url.'" 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{$_})) { - &checkonthis($r,$_,$level+1,'',$fulltext,@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 - -sub search_html_header { - my $Str = <<ENDHEADER; -<html> -<head> -<title>The LearningOnline Network with CAPA</title> -</head> -ENDHEADER - return $Str; -} - -###################################################################### -###################################################################### - -=pod +=pod +=over 4 + =item &print_basic_search_form() Prints the form for the basic search. Sorry the name is so cryptic. @@ -651,124 +453,124 @@ Prints the form for the basic search. S ###################################################################### sub print_basic_search_form { my ($r,$closebutton,$hidden_fields) = @_; - my $result = ($ENV{'form.catalogmode'} ne 'groupsearch'); - my $bodytag=&Apache::loncommon::bodytag('Search'). - &Apache::lonhtmlcommon::breadcrumbs(undef,'Searching','Search_Basic', - undef,undef, - $ENV{'form.catalogmode'} ne 'groupsearch'); - my $scrout = &search_html_header().$bodytag; - if (&Apache::lonnet::allowed('bre',$ENV{'request.role.domain'})) { - # Define interface components - my $userelatedwords= - &mt('[_1] use related words', - &Apache::lonhtmlcommon::checkbox - ('related',$ENV{'form.related'},'related')); - my $onlysearchdomain= - &mt('[_1] only search domain [_2]', - &Apache::lonhtmlcommon::checkbox('domains', - $ENV{'form.domains'}, - $r->dir_config('lonDefDomain') - ), - $r->dir_config('lonDefDomain') - ); - my $adv_search_link = - '<a href="/adm/searchcat?'. - 'phase=disp_adv&'. - 'catalogmode='.$ENV{'form.catalogmode'}. - '&launch='.$ENV{'form.launch'}. - '&mode='.$ENV{'form.mode'}. - '">'.&mt('Advanced Search').'</a>'; - # - $scrout.='<form name="loncapa_search" method="post" '. - 'action="/adm/searchcat">'. - '<input type="hidden" name="phase" value="basic_search" />'. - $hidden_fields; - # - $scrout .= '<center>'.$/; - if ($ENV{'request.course.id'}) { - $scrout .= '<h1>'.&mt('LON-CAPA Catalog Search').'</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', - &HTML::Entities::encode($ENV{'form.basicexp'},'<>&"'),50 - ). - '<br />'. - '<font size="-1">'.&searchhelp().'</font>'.'</td>'. - '<td><font size="-1">'. - '<nobr>'.(' 'x3).$adv_search_link.'</nobr>'.'<br />'. - '<nobr>'.(' 'x1).$userelatedwords.'</nobr>'.'<br />'. - '<nobr>'.(' 'x1).$onlysearchdomain.'</nobr>'.'<br />'. - '</font></td>'. - '</tr>'.$/; - # - $scrout .= '<tr><td align="center" colspan="2">'. - '<font size="-1">'. - '<input type="submit" name="basicsubmit" '. - 'value="'.&mt('Search').'" />'. - (' 'x2).$closebutton.(' 'x2). - &viewoptions(). - '</font>'. - '</td></tr>'.$/; - $scrout .= '</table>'.$/.'</center>'.'</form>'; - } - if ($ENV{'request.course.id'}) { - my %lt=&Apache::lonlocal::texthash('srch' => 'Search', - 'header' => 'Course Search', - 'note' => 'Enter terms or phrases, then press "Search" below', - 'use' => 'use related words', - 'full' =>'fulltext search (time consuming)', - 'disc' => 'search discussion postings (resources and bulletin boards)', - ); - $scrout.=(<<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 -<p> -$lt{'note'}. -</p> -<p> -<table> -<tr><td> -ENDCOURSESEARCH - $scrout.=' '. - &Apache::lonhtmlcommon::textbox('courseexp', - $ENV{'form.courseexp'},40); - my $crscheckbox = - &Apache::lonhtmlcommon::checkbox('crsfulltext', - $ENV{'form.crsfulltext'}); - my $relcheckbox = - &Apache::lonhtmlcommon::checkbox('crsrelated', - $ENV{'form.crsrelated'}); - my $discheckbox = - &Apache::lonhtmlcommon::checkbox('crsdiscuss', - $ENV{'form.crsrelated'}); - $scrout.=(<<ENDENDCOURSE); -</td></tr> -<tr><td>$relcheckbox $lt{'use'}</td><td></td></tr> -<tr><td>$crscheckbox $lt{'full'}</td><td></td></tr> -<tr><td>$discheckbox $lt{'disc'}</td><td></td></tr> -</table><p> - <input type="submit" name="coursesubmit" value='$lt{'srch'}' /> -</p> -</center> -</form> -ENDENDCOURSE - } - $scrout.=(<<ENDDOCUMENT); -</body> -</html> -ENDDOCUMENT + my $result = ($env{'form.catalogmode'} ne 'import'); + my $bread_crumb = + &Apache::lonhtmlcommon::breadcrumbs('Searching','Search_Basic', + $env{'form.catalogmode'} ne 'import'); + my $scrout = &Apache::loncommon::start_page('Content Library').$bread_crumb; +# Search form for resource space + if (&Apache::lonnet::allowed('bre',$env{'request.role.domain'}) eq 'F') { + $scrout .= &setup_basic_search($r,'res',$hidden_fields,$closebutton); + $scrout .= '<hr /><br />'; + } +# Search form for accessible portfolio files + $scrout.= &setup_basic_search($r,'portfolio',$hidden_fields,$closebutton); + $scrout .= &Apache::loncommon::end_page(); $r->print($scrout); return; } + +sub setup_basic_search { + my ($r,$area,$hidden_fields,$closebutton) = @_; + # Define interface components + my %lt = &Apache::lonlocal::texthash ( + res => 'Content Library 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>'; + + my $anydom = 1; + if ($area eq 'res') { + unless (&Apache::lonnet::allowed('bre','/res/') eq 'F') { + $anydom = 0; + } + } + my $singledom; + my ($disabled,$checked); + if ($anydom) { + $singledom = $r->dir_config('lonDefDomain'); + if ($env{'form.domains'} eq $singledom) { + $checked = 1; + } + } else { + $singledom = $env{'user.domain'}; + $disabled = ' disabled="disabled"'; + $checked = 1; + } + $onlysearchdomain = '<label>' + .&Apache::lonhtmlcommon::checkbox( + 'domains',$checked, + $singledom,$disabled) + .' ' + .&mt('only search domain [_1]' + ,'<b>'.$singledom.'</b>') + .'</label>'; + + $adv_search_link = '<a href="/adm/searchcat?'. + &Apache::loncommon::inhibit_menu_check(). + '&phase=disp_adv'. + '&catalogmode='.$env{'form.catalogmode'}. + '&launch='.$env{'form.launch'}. + '&mode='.$env{'form.mode'}. + '&area='.$area. + '&form='.$env{'form.form'}. + '&titleelement='.$env{'form.titleelement'}. + '&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_medium">'.&searchhelp().'</span>'.'</td>'. + '<td>'. + '<span class="LC_nobreak">'.(' 'x3).$adv_search_link.'</span>'.'<br />'. + '<span class="LC_nobreak">'.(' 'x1).$userelatedwords.'</span>'.'<br />'. + '<span class="LC_nobreak">'.(' 'x1).$onlysearchdomain.'</span>'.'<br />'. + '<span class="LC_nobreak">'.(' '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; +} + ###################################################################### ###################################################################### @@ -784,34 +586,59 @@ Prints the advanced search form. ###################################################################### sub print_advanced_search_form{ my ($r,$closebutton,$hidden_fields) = @_; - my $bodytag=&Apache::loncommon::bodytag('Advanced Catalog Search'). - &Apache::lonhtmlcommon::breadcrumbs(undef,'Searching', - 'Search_Advanced', - undef,undef, - $ENV{'form.catalogmode'} ne 'groupsearch'); + 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> <input type="submit" name="advancedsubmit" value='$lt{"srch"}' /> <input type="reset" name="reset" value='$lt{"reset"}' /> $closebutton +</p> END - my $scrout=&search_html_header(); - $scrout .= <<"ENDHEADER"; -$bodytag -<form method="post" action="/adm/searchcat" name="advsearch"> -<p> -$advanced_buttons -ENDHEADER - $scrout.=(' 'x2).&viewoptions().'</p>'.$hidden_fields. - '<input type="hidden" name="phase" value="adv_search" />'; + my $srchtype = 'Content Library'; + my $jscript; + if ($env{'form.area'} eq 'portfolio') { + $srchtype = 'Portfolio'; + $jscript = '<script type="text/javascript"> +// <![CDATA[ +function additional_metadata() { + if (document.advsearch.newfield.checked) { + document.advsearch.phase.value = "disp_adv"; + document.advsearch.numaddedfields.value = parseInt(document.advsearch.numaddedfields.value) +1; + document.advsearch.submit(); + } +} +// ]]> +</script>'; + } + my $scrout= &Apache::loncommon::start_page("Advanced $srchtype Search", + $jscript); + $scrout .= $bread_crumb.'<div class="LC_landmark" role="main">'."\n"; + + $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(); - # - $scrout .= '<h3>'.&mt('Standard Metadata').'</h3>'; - $scrout .= "<table>\n"; - $scrout .= '<tr><td> </td><td colspan="2"><font size="-1">'. - (' 'x2).&searchhelp()."</font></td></tr>\n"; + + # Standard Metadata + $scrout .= &Apache::lonhtmlcommon::row_headline() + .'<h2 class="LC_heading_2">'.&mt("Standard $srchtype Metadata").'</h2>' + .&searchhelp() + .&Apache::lonhtmlcommon::row_closure(); my %related_word_search = ('title' => 1, 'author' => 0, @@ -823,124 +650,220 @@ ENDHEADER 'abstract' => 1, 'standards'=> 1, 'mime' => 1, + 'subject' => 1, ); # - foreach my $field ('title','author','owner','authorspace','modifyinguser', - 'keywords','notes','abstract','standards','mime') { - $scrout.='<tr><td align="right">'.&titlefield($fields{$field}).'</td><td>'. - &Apache::lonmeta::prettyinput($field, - $ENV{'form.'.$field}, + foreach my $field ('title','author','subject','owner','authorspace', + 'modifyinguser','keywords','notes','abstract', + 'standards','mime') { + $scrout .= &Apache::lonhtmlcommon::row_title('<label for="'.$field.'">'. + &titlefield($fields{$field}).'</label>') + .&Apache::lonmeta::prettyinput($field, + $env{'form.'.$field},'', $field, 'advsearch', - $related_word_search{$field}, - '</td><td align="left">', - $ENV{'form.'.$field.'_related'}, + $related_word_search{$field}, + ' ', + $env{'form.'.$field.'_related'}, 50); if ($related_word_search{$field}) { - $scrout .= 'related words'; + $scrout .= '<label for="'.$field.'_related">'.&mt('related words').'</label>'; } else { - $scrout .= '</td><td> '; + $scrout .= ''; } - $scrout .= '</td></tr>'.$/; + $scrout .= &Apache::lonhtmlcommon::row_closure(); } foreach my $field ('lowestgradelevel','highestgradelevel') { - $scrout.='<tr>'. - '<td align="right">'.&titlefield($fields{$field}).'</td>'. - '<td colspan="2">'. - &Apache::lonmeta::prettyinput($field, - $ENV{'form.'.$field}, + $scrout .= &Apache::lonhtmlcommon::row_title('<label for="'.$field.'">'. + &titlefield($fields{$field}).'</label>') + .&Apache::lonmeta::prettyinput($field, + $env{'form.'.$field},'', $field, 'advsearch', - 0). - '</td></tr>'.$/; + 0) + .&Apache::lonhtmlcommon::row_closure(); } - $scrout.='<tr><td align="right">'. - &titlefield(&mt('MIME Type Category')).'</td><td colspan="2">'. - &Apache::loncommon::filecategoryselect('category', - $ENV{'form.category'}). - '</td></tr>'.$/; - $scrout.='<tr><td align="right" valign="top">'. - &titlefield(&mt('Domains')).'</td><td colspan="2">'. - &Apache::loncommon::domain_select('domains', - $ENV{'form.domains'},1). - '</td></tr>'.$/; - # + + $scrout .= &Apache::lonhtmlcommon::row_title('<label for="category">'. + &titlefield(&mt('MIME Type Category')).'</label>') + .&Apache::loncommon::filecategoryselect('category', + $env{'form.category'},'category') + .&Apache::lonhtmlcommon::row_closure(); + + my $anydomain = 1; + if ($env{'form.area'} ne 'portfolio') { + unless (&Apache::lonnet::allowed('bre','/res/')) { + $anydomain = 0; + } + } + + $scrout .= &Apache::lonhtmlcommon::row_title('<label for="domains">'. + &titlefield(&mt('Domains')).'</label>'); + if ($anydomain) { + my $defdom = &Apache::lonnet::default_login_domain(); + my ($trusted,$untrusted) = &Apache::lonnet::trusted_domains('shared',$defdom); + $scrout .= &Apache::loncommon::domain_select('domains', + $env{'form.domains'},1,$trusted,$untrusted,'domains'); + } else { + $scrout .= &Apache::loncommon::select_dom_form($env{'user.domain'}, + 'domains','','','', + [$env{'user.domain'}],'',1,'domains'); + } + $scrout .= &Apache::lonhtmlcommon::row_closure(); + # Misc metadata - $scrout.='<tr><td align="right" valign="top">'. - &titlefield(&mt('Copyright/Distribution')).'</td><td colspan="2">'. - &Apache::lonmeta::selectbox('copyright', - $ENV{'form.copyright'}, - \&Apache::loncommon::copyrightdescription, - ( undef, - &Apache::loncommon::copyrightids) - ).'</td></tr>'.$/; - $scrout.='<tr><td align="right" valign="top">'. - &titlefield(&mt('Language')).'</td><td colspan="2">'. - &Apache::lonmeta::selectbox('language', - $ENV{'form.language'}, + if ($env{'form.area'} ne 'portfolio') { + $scrout .= &Apache::lonhtmlcommon::row_title('<label for="copyright">'. + &titlefield(&mt('Copyright/Distribution')).'</label>') + .&Apache::lonmeta::selectbox('copyright', + $env{'form.copyright'},'', + 'copyright', + \&Apache::loncommon::copyrightdescription, + ( undef, + &Apache::loncommon::copyrightids) + ) + .&Apache::lonhtmlcommon::row_closure(); + } + + $scrout .= &Apache::lonhtmlcommon::row_title('<label for="language">'. + &titlefield(&mt('Language'))'</label>') + .&Apache::lonmeta::selectbox('language', + $env{'form.language'},'','language', \&Apache::loncommon::languagedescription, ('any',&Apache::loncommon::languageids) - ).'</td></tr>'; - $scrout .= "</table>\n"; - # - # Dynamic metadata - $scrout .= '<h3>'.&mt('Problem Statistics').'</h3>'; - $scrout .= "<table>\n"; - $scrout .= '<tr><td> </td><td align="center">'.&mt('Minimum').'</td>'. - '<td align="center">'.&mt('Maximum').'</td></tr>'."\n"; - foreach my $statistic - ({ name=>'count', - description=>'Network-wide number of accesses (hits)',}, - { name=>'stdno', - description=> - 'Total number of students who have worked on this problem',}, - { name => 'avetries', - description=>'Average number of tries till solved',}, - { name => 'difficulty', - description=>'Degree of difficulty',}, - { name => 'disc', - description=>'Degree of discrimination'}) { - $scrout .= '<tr><td align="right">'. - &titlefield(&mt($statistic->{'description'})). - '</td><td align="center">'. - '<input type="text" name="'.$statistic->{'name'}.'_min" '. - 'value="" size="6" />'. - '</td><td align="center">'. - '<input type="text" name="'.$statistic->{'name'}.'_max" '. - 'value="" size="6" />'. - '</td></tr>'.$/; - } - $scrout .= "</table>\n"; - $scrout .= '<h3>'.&mt('Evaluation Data').'</h3>'; - $scrout .= "<table>\n"; - $scrout .= '<tr><td> </td><td align="center">'.&mt('Minimum').'</td>'. - '<td align="center">'.&mt('Maximum').'</td></tr>'."\n"; - 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 .= '<tr><td align="right">'. - &titlefield(&mt($evaluation->{'description'})). - '</td><td align="center">'. - '<input type="text" name="'.$evaluation->{'name'}.'_min" '. - 'value="" size="6" />'. - '</td><td align="center">'. - '<input type="text" name="'.$evaluation->{'name'}.'_max" '. - 'value="" size="6" />'. - '</td></tr>'.$/; + ) + .&Apache::lonhtmlcommon::row_closure(); + + # Portfolio Metadata + if ($env{'form.area'} eq 'portfolio') { + # Added fields + my $curnumadd = $env{'form.numaddedfields'}; + if ($curnumadd eq '') { + $curnumadd = 1; + } + my $customlabel = &mt('Text box description'); + $scrout .= &Apache::lonhtmlcommon::row_headline() + .'<h3>'.&mt('Custom Metadata fields').'</h3>' + .&Apache::lonhtmlcommon::row_closure() + .&Apache::lonhtmlcommon::row_title('<span class="LC_visually_hidden">'.$customlabel.'</span>', + '','','',1) + .&mt('Field Name').' | '.&mt('Field Value(s)') + .&Apache::lonhtmlcommon::row_closure(); + + for (my $j=0; $j<$curnumadd; $j++) { + my $num = $j+1; + my $namelabel = &mt('name of custom metadata field [_1]',$num); + my $valuelabel = &mt('value of custom metadata field [_1]',$num); + $scrout .= &Apache::lonhtmlcommon::row_title(&mt('Custom metadata [_1]',$num)) + .'<input type="text" id="addedfield_'.$j.'"' + .' name="addedfield_'.$j.'" size="10"' + .' value="'.$env{'form.addedfield_'.$j}.'" aria-label="'.$namelabel.'" />' + .' ' + .'<input type="text" ' + .'name="addedvalues_'.$j.'" size="15"' + .' value="'.$env{'form.addedvalues_'.$j}.'" aria-label="'.$valuelabel.'" />' + .&Apache::lonhtmlcommon::row_closure(); + } + my $addcustomlabel = &mt('Add metadata field option'); + $scrout .= &Apache::lonhtmlcommon::row_title('<span class="LC_visually_hidden">'.$addcustomlabel.'</span>', + '','','',1) + .'<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 + my $statslabel = &mt('Text box description'); + $scrout .= &Apache::lonhtmlcommon::row_headline() + .'<h3>'.&mt('Problem Statistics').'</h3>' + .&Apache::lonhtmlcommon::row_closure(); + $scrout .= &Apache::lonhtmlcommon::row_title('<span class="LC_visually_hidden">'.$statslabel.'</span>', + '','','',1) + .&mt('Minimum').' | '.&mt('Maximum') + .&Apache::lonhtmlcommon::row_closure(); + foreach my $statistic + ({ name=>'count', + description=>'Network-wide number of accesses (hits)', + minlabel => 'minimum hit count', + maxlabel => 'maximum hit count'}, + { name=>'stdno', + description=> + 'Statistics calculated for number of students', + minlabel => 'minimum number of students in calculation', + maxlabel => 'maximum number of students in calculation'}, + { name => 'avetries', + description=>'Average number of tries till solved', + minlabel => 'minimum average tries till solved', + maxlabel => 'maximum average tries till solved'}, + { name => 'difficulty', + description=>'Degree of difficulty', + minlabel => 'minimum degree of difficulty', + maxlabel => 'maximum degree of difficulty'}, + { name => 'disc', + description=>'Degree of discrimination', + minlabel => 'minimum degree of discrimination', + maxlabel => 'maximum degree of discrimination'}) { + $scrout .= &Apache::lonhtmlcommon::row_title(&titlefield(&mt($statistic->{'description'}))) + .'<input type="text" name="'.$statistic->{'name'} + .'_min" value="" size="6" aria-label="'.&mt($statistic->{'minlabel'}).'" />' + .' ' + .'<input type="text" name="'.$statistic->{'name'} + .'_max" value="" size="6" aria-label="'.&mt($statistic->{'maxlabel'}).'" />' + .&Apache::lonhtmlcommon::row_closure(); + } + my $evallabel = &mt('Text box description'); + $scrout .= &Apache::lonhtmlcommon::row_headline() + .'<h3>'.&mt('Evaluation Data').'</h3>' + .&Apache::lonhtmlcommon::row_closure(); + $scrout .= &Apache::lonhtmlcommon::row_title('<span class="LC_visually_hidden">'.$evallabel.'</span>', + '','','',1) + .&mt('Minimum').' | '.&mt('Maximum') + .&Apache::lonhtmlcommon::row_closure(); + foreach my $evaluation + ( { name => 'clear', + description => 'Material presented in clear way', + minlabel => 'minimum score: clarity', + maxlabel => 'maximum score: clarity'}, + { name =>'depth', + description => 'Material covered with sufficient depth', + minlabel => 'minimum score: coverage depth', + maxlabel => 'maximum score: coverage depth'}, + { name => 'helpful', + description => 'Material is helpful', + minlabel => 'minimum score: content helpful', + maxlabel => 'maximum score: content helpful'}, + { name => 'correct', + description => 'Material appears to be correct', + minlabel => 'minimum score: correctness', + maxlabel => 'maximum score: correctness'}, + { name => 'technical', + description => 'Resource is technically correct', + minlabel => 'minimum score: technical correctness', + maxlabel => 'maximum score: technical correctness'}) { + $scrout .= &Apache::lonhtmlcommon::row_title(&titlefield(&mt($evaluation->{'description'}))) + .'<input type="text" name="' + .$evaluation->{'name'}.'_min" value="" size="6" aria-label="'.&mt($evaluation->{'minlabel'}).'" />' + .' ' + .'<input type="text" name="' + .$evaluation->{'name'}.'_max" value="" size="6" aria-label="'.&mt($evaluation->{'maxlabel'}).'" />' + .&Apache::lonhtmlcommon::row_closure(); + } } - $scrout .= "</table>\n"; # # Creation/Modification date limits - $scrout .= '<h3>'.&mt('Creation and Modification dates').'</h3>'; - $scrout .= "\n<table>\n"; + my $dateslabel = &mt('Text box description'); + $scrout .= &Apache::lonhtmlcommon::row_headline() + .'<h3>'.&mt('Creation and Modification dates').'</h3>' + .&Apache::lonhtmlcommon::row_closure(); + $scrout .= &Apache::lonhtmlcommon::row_title('<span class="LC_visually_hidden">'.$dateslabel.'</span>', + '','','',1) + .&mt('Month[_1]Day[_2]Year',' 'x14,' 'x6) + .&Apache::lonhtmlcommon::row_closure(); + my $cafter = &Apache::lonhtmlcommon::date_setter('advsearch', # formname 'creationdate1', # fieldname @@ -959,10 +882,13 @@ ENDHEADER '', # state 1, # no_hh_mm_ss ); - $scrout .= &mt('<tr><td align="right">Created between</td>'. - '<td>[_1]</td></tr>'. - '<tr><td align="right">and </td>'. - '<td>[_2]</td></tr>',$cafter,$cbefore); + $scrout .= &Apache::lonhtmlcommon::row_title(&mt('Created between')) + .$cafter + .&Apache::lonhtmlcommon::row_closure(1) + .&Apache::lonhtmlcommon::row_title(&mt('and')) + .$cbefore + .&Apache::lonhtmlcommon::row_closure(); + my $lafter = &Apache::lonhtmlcommon::date_setter('advsearch', 'revisiondate1', @@ -981,17 +907,19 @@ ENDHEADER '', # state 1, # no_hh_mm_ss ); - $scrout .= &mt('<tr><td align="right">Last modified between </td>'. - '<td>[_1]</td></tr>'. - '<tr><td align="right">and</td>'. - '<td>[_2]</td></tr>',$lafter,$lbefore); - $scrout.="</table>\n"; - $scrout.=<<ENDDOCUMENT; -$advanced_buttons -</form> -</body> -</html> -ENDDOCUMENT + $scrout .= &Apache::lonhtmlcommon::row_title(&mt('Last modified between')) + .$lafter + .&Apache::lonhtmlcommon::row_closure(1) + .&Apache::lonhtmlcommon::row_title(&mt('and')) + .$lbefore + .&Apache::lonhtmlcommon::row_closure(1); # Last row of total pick_box + + $scrout .= &Apache::lonhtmlcommon::end_pick_box(); + + $scrout .= $advanced_buttons + .'</form>'; + + $scrout .= '</div>'.&Apache::loncommon::end_page(); $r->print($scrout); return; } @@ -1038,7 +966,9 @@ sub viewoptiontext { 'xml' => 'XML/SGML', 'compact' => 'Compact View', 'fielded' => 'Fielded Format', - 'summary' => 'Summary View'); + 'summary' => 'Summary View', + 'summarypreview' => 'Summary Preview', + 'detailedpreview' => 'Detailed Citation Preview'); return $desc{$code}; } @@ -1059,20 +989,23 @@ Outputs: text for box with view options ###################################################################### sub viewoptions { my $scrout; - if (! defined($ENV{'form.viewselect'})) { - $ENV{'form.viewselect'}='detailed'; + if (! defined($env{'form.viewselect'})) { + $env{'form.viewselect'}='detailed'; } - $scrout.=&Apache::lonmeta::selectbox('viewselect', - $ENV{'form.viewselect'}, - \&viewoptiontext, - sort(keys(%Views))); - $scrout.= ' '; + $scrout .= '<span class="LC_nobreak"><label>' + .&mt('Type:').' ' + .&Apache::lonmeta::selectbox('viewselect', + $env{'form.viewselect'},'','', + \&viewoptiontext, + sort(keys(%Views))) + .'</label></span>'; my $countselect = &Apache::lonmeta::selectbox('show', - $ENV{'form.show'}, + $env{'form.show'},'','', undef, (10,20,50,100,1000,10000)); - $scrout .= (' 'x2).&mt('[_1] Records per Page',$countselect). - '</nobr>'.$/; + $scrout .= ' <span class="LC_nobreak"><label>' + .&mt('Records per Page:').' '.$countselect + .'</label></span>'.$/; return $scrout; } @@ -1108,7 +1041,7 @@ Outputs: returns undef on database error 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 +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. @@ -1130,20 +1063,20 @@ sub get_persistent_form_data { next if ($name !~ /^form./); # Kludgification begins! if ($name eq 'form.domains' && - $ENV{'form.searchmode'} eq 'basic' && - $ENV{'form.phase'} ne 'disp_basic') { + $env{'form.searchmode'} eq 'basic' && + $env{'form.phase'} ne 'disp_basic') { next; } # End kludge (hopefully) - next if (exists($ENV{$name})); + next if (exists($env{$name})); my @values = map { - &Apache::lonnet::unescape($_); + &unescape($_); } split(',',$persistent_db{$name}); next if (@values <1); if ($arrays_allowed{$name}) { - $ENV{$name} = [@values]; + $env{$name} = [@values]; } else { - $ENV{$name} = $values[0] if ($values[0]); + $env{$name} = $values[0] if ($values[0]); } } untie (%persistent_db); @@ -1163,8 +1096,9 @@ Outputs: array of values. Returns undef 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. +values unescaped. If the item is 'domains; then the returned +value will be a hash pointer. Otherwise, if the item contains +commas (before unescaping), the returned value will be an array pointer. =cut @@ -1182,13 +1116,25 @@ sub get_persistent_data { push @Values, undef; next; } - my @values = map { - &Apache::lonnet::unescape($_); - } split(',',$persistent_db{$name}); - if (@values <= 1) { - push @Values,$values[0]; + if ($name eq 'domains') { + my %valueshash; + my @items= map { &unescape($_); } split(',',$persistent_db{$name}); + foreach my $item (@items) { + if ($item =~ /=/) { + my ($key,$val) = map { &unescape($_); } split(/=/,$item); + $valueshash{$key} = $val; + } + } + push(@Values,\%valueshash); } else { - push @Values,\@values; + my @values = map { + &unescape($_); + } split(',',$persistent_db{$name}); + if (@values <= 1) { + push @Values,$values[0]; + } else { + push @Values,\@values; + } } } untie (%persistent_db); @@ -1206,7 +1152,9 @@ Inputs: Hash of values to save, filename 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 separated string. +elements escaped and concatenated in a comma separated string. Values +that are hash pointers will have their keys and values escaped and +concatenated in a comma separated string. =cut @@ -1218,9 +1166,18 @@ sub make_persistent { return undef if (! tie(%persistent_db,'GDBM_File', $filename,&GDBM_WRCREAT(),0640)); foreach my $name (keys(%save)) { - my @values = (ref($save{$name}) ? @{$save{$name}} : ($save{$name})); - # We handle array references, but not recursively. - my $store = join(',', map { &Apache::lonnet::escape($_); } @values ); + my @values=(); + if (ref($save{$name}) eq 'ARRAY') { + @values = @{$save{$name}}; + } elsif (ref($save{$name}) eq 'HASH') { + foreach my $key (%{$save{$name}}) { + push(@values,&escape($key).'='.&escape($save{$name}{$key})); + } + } else { + @values = $save{$name}; + } + # We handle array and hash references, but not recursively. + my $store = join(',', map { &escape($_); } @values ); $persistent_db{$name} = $store; } untie(%persistent_db); @@ -1248,9 +1205,9 @@ sub make_form_data_persistent { my $r = shift; my $filename = shift; my %save; - foreach (keys(%ENV)) { + foreach (keys(%env)) { next if (!/^form/ || /submit/); - $save{$_} = $ENV{$_}; + $save{$_} = $env{$_}; } return &make_persistent(\%save,$filename); } @@ -1298,39 +1255,50 @@ sub parse_advanced_search { 'lastrevisiondatestart_month','lastrevisiondatestart_day', 'lastrevisiondatestart_year','lastrevisiondateend_month', 'lastrevisiondateend_day','lastrevisiondateend_year') { - $ENV{'form.'.$field}=~s/[^\w\/\s\(\)\=\-\"\']//g; + $env{'form.'.$field}=~s/[^\w\/\s\(\)\=\-\"\'.\*]//g; } foreach ('mode','form','element') { # is this required? Hmmm. - next if (! exists($ENV{'form.'.$_})); - $ENV{'form.'.$_}=&Apache::lonnet::unescape($ENV{'form.'.$_}); - $ENV{'form.'.$_}=~s/[^\w\/\s\(\)\=\-\"\']//g; + next if (! exists($env{'form.'.$_})); + $env{'form.'.$_}=&unescape($env{'form.'.$_}); + $env{'form.'.$_}=~s/[^\w\/\s\(\)\=\-\"\']//g; } # Preprocess the category form element. - $ENV{'form.category'} = 'any' if (! defined($ENV{'form.category'}) || - ref($ENV{'form.category'})); + $env{'form.category'} = 'any' if (! defined($env{'form.category'}) || + ref($env{'form.category'})); # # Check to see if enough information was filled in foreach my $field (@BasicFields) { - if (&filled($ENV{'form.'.$field})) { + if (&filled($env{'form.'.$field})) { $fillflag++; } } foreach my $field (@StatsFields,@EvalFields) { - if (&filled($ENV{'form.'.$field.'_max'})) { + if (&filled($env{'form.'.$field.'_max'})) { $fillflag++; } - if (&filled($ENV{'form.'.$field.'_min'})) { + if (&filled($env{'form.'.$field.'_min'})) { $fillflag++; } } for my $field ('lowestgradelevel','highestgradelevel') { - if ( $ENV{'form.'.$field} =~ /^\d+$/ && - $ENV{'form.'.$field} > 0) { + 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); @@ -1342,21 +1310,21 @@ sub parse_advanced_search { my $font = '<font color="#800000" face="helvetica">'; # Evaluate logical expression AND/OR/NOT phrase fields. foreach my $field (@BasicFields) { - next if (!defined($ENV{'form.'.$field}) || $ENV{'form.'.$field} eq ''); + next if (!defined($env{'form.'.$field}) || $env{'form.'.$field} eq ''); my ($error,$SQLQuery) = - &process_phrase_input($ENV{'form.'.$field}, - $ENV{'form.'.$field.'_related'},$field); + &process_phrase_input($env{'form.'.$field}, + $env{'form.'.$field.'_related'},$field); if (defined($error)) { &output_unparsed_phrase_error($r,$closebutton,'phase=disp_adv', $hidden_fields,$field); return; } else { $pretty_search_string .= - $font.$field.'</font>: '.$ENV{'form.'.$field}; - if ($ENV{'form.'.$field.'_related'}) { + $font.$field.'</font>: '.$env{'form.'.$field}; + if ($env{'form.'.$field.'_related'}) { my @Words = &Apache::loncommon::get_related_words - ($ENV{'form.'.$field}); + ($env{'form.'.$field}); if (@Words) { $pretty_search_string.= ' with related words: '. join(', ',@Words[0..4]); @@ -1372,11 +1340,11 @@ sub parse_advanced_search { # Make the 'mime' from 'form.category' and 'form.extension' # my $searchphrase; - if (exists($ENV{'form.category'}) && - $ENV{'form.category'} !~ /^\s*$/ && - $ENV{'form.category'} ne 'any') { + if (exists($env{'form.category'}) && + $env{'form.category'} !~ /^\s*$/ && + $env{'form.category'} ne 'any') { my @extensions = &Apache::loncommon::filecategorytypes - ($ENV{'form.category'}); + ($env{'form.category'}); if (scalar(@extensions) > 0) { $searchphrase = join(' OR ',@extensions); } @@ -1389,57 +1357,84 @@ sub parse_advanced_search { } # # Evaluate option lists - if ($ENV{'form.lowestgradelevel'} && - $ENV{'form.lowestgradelevel'} ne '0' && - $ENV{'form.lowestgradelevel'} =~ /^\d+$/) { + if ($env{'form.lowestgradelevel'} && + $env{'form.lowestgradelevel'} ne '0' && + $env{'form.lowestgradelevel'} =~ /^\d+$/) { push(@queries, - '(lowestgradelevel>='.$ENV{'form.lowestgradelevel'}.')'); + '(lowestgradelevel>='.$env{'form.lowestgradelevel'}.')'); $pretty_search_string.="lowestgradelevel>=". - $ENV{'form.lowestgradelevel'}."<br />\n"; + $env{'form.lowestgradelevel'}."<br />\n"; } - if ($ENV{'form.highestgradelevel'} && - $ENV{'form.highestgradelevel'} ne '0' && - $ENV{'form.highestgradelevel'} =~ /^\d+$/) { + if ($env{'form.highestgradelevel'} && + $env{'form.highestgradelevel'} ne '0' && + $env{'form.highestgradelevel'} =~ /^\d+$/) { push(@queries, - '(highestgradelevel<='.$ENV{'form.highestgradelevel'}.')'); + '(highestgradelevel<='.$env{'form.highestgradelevel'}.')'); $pretty_search_string.="highestgradelevel<=". - $ENV{'form.highestgradelevel'}."<br />\n"; + $env{'form.highestgradelevel'}."<br />\n"; } - if ($ENV{'form.language'} and $ENV{'form.language'} ne 'any') { - push @queries,"(language like \"$ENV{'form.language'}\")"; + if ($env{'form.language'} and $env{'form.language'} ne 'any') { + push @queries,"(language like \"$env{'form.language'}\")"; $pretty_search_string.=$font."language</font>= ". - &Apache::loncommon::languagedescription($ENV{'form.language'}). + &Apache::loncommon::languagedescription($env{'form.language'}). "<br />\n"; } - if ($ENV{'form.copyright'} and $ENV{'form.copyright'} ne 'any') { - push @queries,"(copyright like \"$ENV{'form.copyright'}\")"; + if ($env{'form.copyright'} and $env{'form.copyright'} ne 'any') { + push @queries,"(copyright like \"$env{'form.copyright'}\")"; $pretty_search_string.=$font."copyright</font> = ". - &Apache::loncommon::copyrightdescription($ENV{'form.copyright'}). + &Apache::loncommon::copyrightdescription($env{'form.copyright'}). "<br />\n"; } - # - # 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>>'.$min.'<br />'; - } - if (defined($max) && $max =~ /^(\d+\.\d+|\d+|\.\d+)$/) { - push(@queries,'('.$field.'<'.$max.')'); - $pretty_search_string.=$font.$field.'</font><'.$max.'<br />'; + 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>>'.$min.'<br />'; + } + if (defined($max) && $max =~ /^(\d+\.\d+|\d+|\.\d+)$/) { + push(@queries,'('.$field.'<'.$max.')'); + $pretty_search_string.=$font.$field.'</font><'.$max.'<br />'; + } } } # @@ -1480,17 +1475,17 @@ sub parse_advanced_search { ## because I was unable to figureout exactly how it worked and could ## not imagine people actually using it. MH ## - # if ($ENV{'form.custommetadata'}) { + # if ($env{'form.custommetadata'}) { # $pretty_search_string .=$font."Custom Metadata Search</font>: <b>". - # $ENV{'form.custommetadata'}."</b><br />\n"; + # $env{'form.custommetadata'}."</b><br />\n"; # $customquery=&build_custommetadata_query('custommetadata', - # $ENV{'form.custommetadata'}); + # $env{'form.custommetadata'}); # } my $customshow=undef; - # if ($ENV{'form.customshow'}) { + # if ($env{'form.customshow'}) { # $pretty_search_string .=$font."Custom Metadata Display</font>: <b>". - # $ENV{'form.customshow'}."</b><br />\n"; - # $customshow=$ENV{'form.customshow'}; + # $env{'form.customshow'}."</b><br />\n"; + # $customshow=$env{'form.customshow'}; # $customshow=~s/[^\w\s]//g; # my @fields=split(/\s+/,$customshow); # $customshow=join(" ",@fields); @@ -1498,33 +1493,35 @@ sub parse_advanced_search { ## ## Deal with restrictions to given domains ## - my ($libraries_to_query,$pretty_domains_string) = + my ($libraries_to_query,$pretty_domains_string,$domains_to_query) = &parse_domain_restrictions(); - $pretty_search_string .= $pretty_domains_string."<br />\n"; + if ($pretty_domains_string) { + $pretty_search_string .= $pretty_domains_string."<br />\n"; + } # if (@queries) { - $query="SELECT * FROM metadata WHERE (".join(") AND (",@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('query = '.$/.$query); + #&Apache::lonnet::logthis('advanced query = '.$/.$query); return ($query,$customquery,$customshow,$libraries_to_query, - $pretty_search_string); + $pretty_search_string,$domains_to_query); } sub parse_domain_restrictions { my $libraries_to_query = undef; - # $ENV{'form.domains'} can be either a scalar or an array reference. + my $domains_to_query = undef; + # $env{'form.domains'} can be either a scalar or an array reference. # We need an array. - if (! exists($ENV{'form.domains'}) || $ENV{'form.domains'} eq '') { - return (undef,''); - } - my @allowed_domains; - if (ref($ENV{'form.domains'})) { - @allowed_domains = @{$ENV{'form.domains'}}; - } else { - @allowed_domains = ($ENV{'form.domains'}); + if (! exists($env{'form.domains'}) || $env{'form.domains'} eq '') { + return (undef,'',undef); } + my @allowed_domains = &Apache::loncommon::get_env_multiple('form.domains'); # my %domain_hash = (); my $pretty_domains_string; @@ -1532,23 +1529,42 @@ sub parse_domain_restrictions { $domain_hash{$_}++; } if ($domain_hash{'any'}) { - $pretty_domains_string = "In all LON-CAPA domains."; + $pretty_domains_string = &mt("in all LON-CAPA domains."); } else { if (@allowed_domains > 1) { - $pretty_domains_string = "In LON-CAPA domains:"; + $pretty_domains_string = &mt("in LON-CAPA domains:"); } else { - $pretty_domains_string = "In LON-CAPA domain "; + $pretty_domains_string = &mt("in LON-CAPA domain "); } foreach (sort @allowed_domains) { $pretty_domains_string .= "<b>".$_."</b> "; } - foreach (keys(%Apache::lonnet::libserv)) { - if (exists($domain_hash{$Apache::lonnet::hostdom{$_}})) { - push @$libraries_to_query,$_; + my %library_servers = &Apache::lonnet::get_unique_servers(\@allowed_domains, + 'library'); + my (%older_library_servers,%okdoms,%domains_for_id); + map { $okdoms{$_} = 1; } @allowed_domains; + foreach my $key (keys(%library_servers)) { + if (&Apache::lonnet::get_server_loncaparev('',$key) =~ /^\'?(\d+)\.(\d+)/) { + my $major = $1; + my $minor = $2; + if (($major < 2) || (($major == 2) && ($minor < 11))) { + map { $older_library_servers{$_} = 1; } + &Apache::lonnet::machine_ids($library_servers{$key}); + } else { + my %possdoms; + map { $possdoms{$_}=1 if ($okdoms{$_}); } + &Apache::lonnet::machine_domains($library_servers{$key}); + $domains_for_id{$key} = join(',',sort(keys(%possdoms))); + } } } - } - return ($libraries_to_query,$pretty_domains_string); + my %servers = (%library_servers,%older_library_servers); + $libraries_to_query = [keys(%servers)]; + $domains_to_query = \%domains_for_id; + } + return ($libraries_to_query, + $pretty_domains_string, + $domains_to_query); } ###################################################################### @@ -1569,31 +1585,34 @@ sub parse_basic_search { # # Clean up fields for safety for my $field ('basicexp') { - $ENV{"form.$field"}=~s/[^\w\s\'\"\!\(\)\-]//g; + $env{"form.$field"}=~s/[^\w\s\'\"\!\(\)\-\*]//g; } foreach ('mode','form','element') { # is this required? Hmmm. - next unless (exists($ENV{"form.$_"})); - $ENV{"form.$_"}=&Apache::lonnet::unescape($ENV{"form.$_"}); - $ENV{"form.$_"}=~s/[^\w\/\s\(\)\=\-\"\']//g; + next unless (exists($env{"form.$_"})); + $env{"form.$_"}=&unescape($env{"form.$_"}); + $env{"form.$_"}=~s/[^\w\/\s\(\)\=\-\"\']//g; } - my ($libraries_to_query,$pretty_domains_string) = + my ($libraries_to_query,$pretty_domains_string,$domains_to_query) = &parse_domain_restrictions(); # # Check to see if enough of a query is filled in - my $search_string = $ENV{'form.basicexp'}; + my $search_string = $env{'form.basicexp'}; if (! &filled($search_string)) { &output_blank_field_error($r,$closebutton,'phase=disp_basic'); return OK; } my $pretty_search_string=$search_string; my @Queries; - my $searchfield = 'concat_ws(" ",'.join(',', - ('title','author','subject', - 'notes','abstract','keywords') - ).')'; + my @fields = ('title','author','subject','notes','abstract','keywords'); + my $searchfield; + if ($env{'form.area'} eq 'portfolio') { + $searchfield = 'concat_ws(" ",pm.'.join(',pm.',@fields).')'; + } else { + $searchfield = 'concat_ws(" ",'.join(',',@fields).')'; + } my ($error,$SQLQuery) = &process_phrase_input($search_string, - $ENV{'form.related'}, + $env{'form.related'}, $searchfield); if ($error) { &output_unparsed_phrase_error($r,$closebutton,'phase=disp_basic', @@ -1604,16 +1623,24 @@ sub parse_basic_search { #foreach my $q (@Queries) { # &Apache::lonnet::logthis(' '.$q); #} - my $final_query = 'SELECT * FROM metadata WHERE '.join(" AND ",@Queries); + 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; } $pretty_search_string .= "<br />\n"; $pretty_search_string =~ s:^<br /> and ::; - # &Apache::lonnet::logthis($final_query); + &Apache::lonnet::logthis('simple search final query = '.$/.$final_query); return ($final_query,$pretty_search_string, - $libraries_to_query); + $libraries_to_query,$domains_to_query); } @@ -1714,7 +1741,7 @@ sub process_phrase_input { $item[1]; } term: - /[\w\Q:!@#$%^&*()+_=|{}<>,.;\\\/?\E]+/ { + /[\w\Q:!@#$%^&*()+_=|{}<>,.;\\\/?\E\-]+/ { $item[1]; } ENDGRAMMAR @@ -1885,14 +1912,14 @@ sub build_date_queries { if ((defined($cafter) && ! defined($cbefore)) || (defined($cbefore) && ! defined($cafter))) { # This is bad, so let them know - $error = &mt('Incorrect entry for the creation date. '. + $error = &mt('Incorrect entry for the creation date. '. 'You must specify both the beginning and ending dates.'); } if (! defined($error) && ((defined($mafter) && ! defined($mbefore)) || (defined($mbefore) && ! defined($mafter)))) { # This is also bad, so let them know - $error = &mt('Incorrect entry for the last revision date. '. + $error = &mt('Incorrect entry for the last revision date. '. 'You must specify both the beginning and ending dates.'); } if (! defined($error)) { @@ -1904,6 +1931,8 @@ sub build_date_queries { my (undef,undef,undef,$cbday,$cbmon,$cbyear) = localtime($cbefore); # Correct for year being relative to 1900 $cayear+=1900; $cbyear+=1900; + # Correct month; localtime gives month 0..11 but MySQL expects 1..12 + $camon++; $cbmon++; my $cquery= '(creationdate BETWEEN '. "'".$cayear.'-'.$camon.'-'.$caday."'". @@ -1922,6 +1951,8 @@ sub build_date_queries { my (undef,undef,undef,$mbday,$mbmon,$mbyear) = localtime($mbefore); # Correct for year being relative to 1900 $mayear+=1900; $mbyear+=1900; + # Correct month; localtime gives month 0..11 but MySQL expects 1..12 + $mamon++; $mbmon++; my $mquery= '(lastrevisiondate BETWEEN '. "'".$mayear.'-'.$mamon.'-'.$maday."'". @@ -1964,16 +1995,21 @@ sub copyright_check { my (undef,undef,$resdom,$resname) = split('/', $Metadata->{'url'}); # Check for priv - if (($Metadata->{'copyright'} eq 'priv') && - (($ENV{'user.name'} ne $resname) && - ($ENV{'user.domain'} ne $resdom))) { - return 0; + if ($Metadata->{'copyright'} eq 'priv') { + unless (($env{'user.name'} eq $resname) && + ($env{'user.domain'} eq $resdom)) { + return 0; + } } # Check for domain if (($Metadata->{'copyright'} eq 'domain') && - ($ENV{'user.domain'} ne $resdom)) { + ($env{'user.domain'} ne $resdom)) { return 0; } + # Check for custom rights + if ($Metadata->{'copyright'} eq 'custom') { + return &Apache::lonnet::customaccess('bre',$Metadata->{'url'}); + } return 1; } @@ -2001,9 +2037,15 @@ sub ensure_db_and_table { ## Sanity check the table id. ## if (! defined($table) || $table eq '' || $table =~ /\D/ ) { - $r->print("Unable to retrieve search results. ". - "Unable to determine the table results were stored in. ". - "</body></html>"); + $r->print(&Apache::loncommon::start_page('Error') + .'<p class="LC_error">' + .&mt('Unable to retrieve search results. ' + .'Unable to determine the table results were saved in.') + .'</p>' + . '<p>'.&mt('Internal info:').'</p>' + .'<pre>'.$table.'</pre>' + .&Apache::loncommon::end_page() + ); return undef; } ## @@ -2011,8 +2053,12 @@ sub ensure_db_and_table { ## my $connection_result = &Apache::lonmysql::connect_to_db(); if (!defined($connection_result)) { - $r->print("Unable to connect to the MySQL database where your results". - " are stored. </body></html>"); + $r->print( + '<p class="LC_error">' + .&mt('Unable to connect to the MySQL database where your results are saved.') + .'</p>' + .&Apache::loncommon::end_page() + ); &Apache::lonnet::logthis("lonsearchcat: unable to get lonmysql to". " connect to database."); &Apache::lonnet::logthis(&Apache::lonmysql::get_error()); @@ -2020,12 +2066,20 @@ sub ensure_db_and_table { } my $table_check = &Apache::lonmysql::check_table($table); if (! defined($table_check)) { - $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 status". " of table ".$table); return undef; } elsif (! $table_check) { - $r->print("The table of results could not be found."); + $r->print( + '<p class="LC_error">' + .&mt('The table of results could not be found.') + .'</p>' + ); &Apache::lonnet::logthis("The user requested a table, ".$table. ", that could not be found."); return undef; @@ -2048,11 +2102,7 @@ a link to change the search query. ###################################################################### ###################################################################### sub print_sort_form { - my ($r,$pretty_query_string) = @_; - my $bodytag=&Apache::loncommon::bodytag(undef,undef,undef,1). - &Apache::lonhtmlcommon::breadcrumbs - (undef,'Searching','Searching',undef,undef, - $ENV{'form.catalogmode'} ne 'groupsearch'); + my ($r,$pretty_query_string,$target) = @_; ## my %SortableFields=&Apache::lonlocal::texthash( @@ -2071,62 +2121,56 @@ sub print_sort_form { lastrevisiondate => 'Revision Date' ); ## - my $table = $ENV{'form.table'}; + my $table = $env{'form.table'}; return if (! &ensure_db_and_table($r,$table)); ## ## Get the number of results ## my $total_results = &Apache::lonmysql::number_of_rows($table); 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". " of rows in table ".$table); &Apache::lonnet::logthis(&Apache::lonmysql::get_error()); return; } - my $result; - $result.=<<END; -<html> -<head> -<script> - function change_sort() { - var newloc = "/adm/searchcat?phase=results"; - newloc += "&persistent_db_id=$ENV{'form.persistent_db_id'}"; - newloc += "&sortby="; - newloc += document.forms.statusform.elements.sortby.value; - parent.resultsframe.location= newloc; - } -</script> -<title>Results</title> -</head> -$bodytag -<form name="statusform" action="" method="post"> -<input type="hidden" name="Queue" value="" /> + my $args; + if ($target eq '_parent') { + $args = {'links_target' => $target}; + } + my $start_page = &Apache::loncommon::start_page('Results',undef,$args); + my $breadcrumbs= + &Apache::lonhtmlcommon::breadcrumbs('Searching','Searching', + $env{'form.catalogmode'} ne 'import', + '','','','','','',$target); + + my $result = <<END; +$start_page +$breadcrumbs +<form name="statusform" action="" method="post" target="$target"> +<input type="hidden" name="catalogmode" value="import" /> +<input type="hidden" name="acts" value="" /> END #<h2>Sort Results</h2> #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)) { # $result.="<option name=\"$_\""; -# if ($_ eq $ENV{'form.sortby'}) { +# if ($_ eq $env{'form.sortby'}) { # $result.=" selected "; # } # $result.=" >$SortableFields{$_}</option>\n"; # } # $result.="</select>\n"; my $revise = &revise_button(); - $result.=<<END; -<p> -There are $total_results matches to your query. $revise -</p><p> -Search:$pretty_query_string -</p> -</form> -</body> -</html> -END - $r->print($result); + $result.='<p>' + .&mt('Total of [quant,_1,match,matches] to your query.',$total_results) + .' '.$revise.'</p>' + .'<p>'.&mt('Search: ').$pretty_query_string + .'</p></form>'; + $r->print($result.&Apache::loncommon::end_page()); return; } @@ -2160,9 +2204,9 @@ my @Fullindicies; =item &create_results_table() 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. @@ -2171,8 +2215,9 @@ Returns: the identifier of the table on ###################################################################### ###################################################################### sub set_up_table_structure { + my ($tabletype) = @_; my ($datatypes,$fullindicies) = - &LONCAPA::lonmetadata::describe_metadata_storage(); + &LONCAPA::lonmetadata::describe_metadata_storage($tabletype); # Copy the table description before modifying it... @Datatypes = @{$datatypes}; unshift(@Datatypes,{name => 'id', @@ -2185,13 +2230,18 @@ sub set_up_table_structure { } sub create_results_table { - &set_up_table_structure(); + my ($area) = @_; + if ($area eq 'portfolio') { + &set_up_table_structure('portfolio_search'); + } else { + &set_up_table_structure('metadata'); + } my $table = &Apache::lonmysql::create_table ( { columns => \@Datatypes, FULLTEXT => [{'columns' => \@Fullindicies},], } ); if (defined($table)) { - $ENV{'form.table'} = $table; + $env{'form.table'} = $table; return $table; } return undef; # Error... @@ -2229,21 +2279,46 @@ Returns: Nothing. sub update_count_status { my ($r,$text) = @_; $text =~ s/\'/\\\'/g; - $r->print - ("<script>document.statusform.count.value = ' $text'</script>\n"); + $r->print(<<SCRIPT); +<script type="text/javascript"> +// <![CDATA[ +document.statusform.count.value = ' $text' +// ]]> +</script> +SCRIPT + $r->rflush(); } sub update_status { my ($r,$text) = @_; $text =~ s/\'/\\\'/g; - $r->print - ("<script>document.statusform.status.value = ' $text'</script>\n"); + $r->print(<<SCRIPT); +<script type="text/javascript"> +// <![CDATA[ +document.statusform.status.value = ' $text' +// ]]> +</script> +SCRIPT + + $r->rflush(); +} + +sub reload_result_frame { + my ($r) = @_; + my $newloc = '/adm/searchcat?phase=results&persistent_db_id='. + $env{'form.persistent_db_id'}; + $r->print(<<SCRIPT); +<script type="text/javascript"> + parent.update_results("$newloc"); +</script> +SCRIPT + $r->rflush(); } { - my $max_time = 40; # seconds for the search to complete + my $max_time = 60; # seconds for the search to complete my $start_time = 0; my $last_time = 0; @@ -2265,9 +2340,14 @@ sub update_seconds { my ($r) = @_; my $time = &time_left(); if (($last_time-$time) > 0) { - $r->print("<script>". - "document.statusform.seconds.value = '$time'". - "</script>\n"); + $r->print(<<SCRIPT); +<script type="text/javascript"> +// <![CDATA[ +document.statusform.seconds.value = '$time' +// ]]> +</script> +SCRIPT + $r->rflush(); } $last_time = $time; @@ -2291,14 +2371,15 @@ Returns: html string for a 'revise searc ###################################################################### ###################################################################### sub revise_button { + my $revisetext = &mt('Revise search'); 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'. - '?persistent_db_id='.$ENV{'form.persistent_db_id'}. - '&cleargroupsort=1'. - '&phase='.$revise_phase; - my $result = qq{<input type="button" value="Revise search" name="revise"} . - qq{ onClick="parent.location='$newloc';" /> }; + '?persistent_db_id='.$env{'form.persistent_db_id'}. + '&cleargroupsort=1'. + '&phase='.$revise_phase; + my $result = qq{<input type="button" value="$revisetext" name="revise"} . + qq{ onclick="parent.location='$newloc';" /> }; return $result; } @@ -2317,21 +2398,28 @@ results into MySQL. ###################################################################### ###################################################################### sub run_search { - my ($r,$query,$customquery,$customshow,$serverlist,$pretty_string) = @_; - my $bodytag=&Apache::loncommon::bodytag(undef,undef,undef,1); - $bodytag.=&Apache::lonhtmlcommon::breadcrumbs - (undef,'Searching','Searching',undef,undef, - $ENV{'form.catalogmode'} ne 'groupsearch'); + my ($r,$query,$customquery,$customshow,$serverlist, + $pretty_string,$area,$domainsref,$target) = @_; + my $tabletype = 'metadata'; + if ($area eq 'portfolio') { + $tabletype = 'portfolio_search'; + } my $connection = $r->connection; # # Print run_search header # + my $args; + if ($target eq '_parent') { + $args = {'links_target' => $target}; + } + my $start_page = &Apache::loncommon::start_page('Search Status',undef,$args); + my $breadcrumbs = + &Apache::lonhtmlcommon::breadcrumbs('Searching','Searching', + $env{'form.catalogmode'} ne 'import', + '','','','','','',$target); $r->print(<<END); -<html> -<head><title>Search Status</title></head> -$bodytag -<form name="statusform" action="" method="post"> -<input type="hidden" name="Queue" value="" /> +$start_page +$breadcrumbs END # Remove leading and trailing <br /> $pretty_string =~ s:^\s*<br />::i; @@ -2342,36 +2430,60 @@ END pop(@Lines); } if (@Lines > 2) { - $pretty_string = join '<br />',(@Lines[0..2],'....<br />'); + $pretty_string = join '<br />',(@Lines[0..2],'...<br />'); } $r->print(&mt("Search: [_1]",$pretty_string)); $r->rflush(); # # Determine the servers we need to contact. - my @Servers_to_contact; + my (@Servers_to_contact,%domains_by_server); if (defined($serverlist)) { if (ref($serverlist) eq 'ARRAY') { @Servers_to_contact = @$serverlist; } else { @Servers_to_contact = ($serverlist); } + if (ref($domainsref) eq 'HASH') { + foreach my $server (@Servers_to_contact) { + $domains_by_server{$server} = $domainsref->{$server}; + } + } } else { - @Servers_to_contact = sort(keys(%Apache::lonnet::libserv)); + my %library_servers = &Apache::lonnet::unique_library(); + my (%all_library_servers, %older_library_servers); + foreach my $key (keys(%library_servers)) { + if (&Apache::lonnet::get_server_loncaparev('',$key) =~ /^\'?(\d+)\.(\d+)/) { + my $major = $1; + my $minor = $2; + if (($major < 2) || (($major == 2) && ($minor < 11))) { + map { $older_library_servers{$_} = 1; } + &Apache::lonnet::machine_ids($library_servers{$key}); + } + } + } + %all_library_servers = (%library_servers,%older_library_servers); + @Servers_to_contact = sort(keys(%all_library_servers)); + foreach my $server (@Servers_to_contact) { + $domains_by_server{$server} = + join(',',sort(&Apache::lonnet::machine_domains($all_library_servers{$server}))); + } } my %Server_status; # # Check on the mysql table we will use to store results. - my $table =$ENV{'form.table'}; + my $table =$env{'form.table'}; if (! defined($table) || $table eq '' || $table =~ /\D/ ) { - $r->print("Unable to determine table id to store search results in.". - "The search has been aborted.</body></html>"); + $r->print("Unable to determine table id to save search results in.". + "The search has been aborted.". + &Apache::loncommon::end_page()); return; } my $table_status = &Apache::lonmysql::check_table($table); 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 ". - "$ENV{'user.name'} @ $ENV{'user.domain'}"); + "$env{'user.name'} @ $env{'user.domain'}"); &Apache::lonnet::logthis("lonmysql error = ". &Apache::lonmysql::get_error()); return; @@ -2383,27 +2495,35 @@ END &Apache::lonmysql::get_debug()); &Apache::lonnet::logthis('table status = "'.$table_status.'"'); $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; } ## ## Prepare for the big loop. my $hitcountsum; + my $oldhitcountsum; + my $displaycount; + my %matches; my $server; my $status; my $revise = &revise_button(); - $r->print(<<END); -<table> -<tr><th>Status</th><th>Total Matches</th><th>Time Remaining</th><th></th></tr> -<tr> -<td><input type="text" name="status" value="" size="30" /></td> -<td><input type="text" name="count" value="" size="10" /></td> -<td><input type="text" name="seconds" value="" size="8" /></td> -<td>$revise</td> -</tr> -</table> -</form> -END + $r->print('<form name="statusform" action="" method="post">'."\n". + '<input type="hidden" name="acts" value="" />'."\n". + '<table border="0"><tr><td>'."\n". + &Apache::loncommon::start_data_table()); + $r->print(&Apache::loncommon::start_data_table_header_row() + .'<th>'.&mt('Status').'</th>' + .'<th>'.&mt('Total Matches').'</th>' + .'<th>'.&mt('Time Remaining').'</th>' + .&Apache::loncommon::end_data_table_header_row() + .&Apache::loncommon::start_data_table_row() + .'<td><input type="text" name="status" value="" size="50" readonly="readonly" /></td>' + .'<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> </td><td>'.$revise.'</td></tr></table></form>'); $r->rflush(); &reset_timing(); &update_seconds($r); @@ -2418,7 +2538,7 @@ END my $server = shift(@Servers_to_contact); &update_status($r,&mt('contacting [_1]',$server)); my $reply=&Apache::lonnet::metadata_query($query,$customquery, - $customshow,[$server]); + $customshow,[$server],\%domains_by_server); ($server) = keys(%$reply); $Server_status{$server} = $reply->{$server}; } else { @@ -2430,7 +2550,7 @@ END &update_status($r, &mt('waiting on [_1]',join(' ',keys(%Server_status)))); } - sleep(1); + sleep(0.1); } # # Loop through the servers we have contacted but do not @@ -2443,8 +2563,11 @@ END delete ($Server_status{$server}); next; } - $status=~/^([\.\w]+)$/; - my $datafile=$r->dir_config('lonDaemons').'/tmp/'.$1; + $status=~s|/||g; + + + + my $datafile=LONCAPA::tempdir().$status; if (-e $datafile && ! -e "$datafile.end") { &update_status($r,&mt('Receiving results from [_1]',$server)); next; @@ -2472,11 +2595,18 @@ END next if (! $result); # # Parse the result. - my %Fields = &parse_raw_result($result,$server); + my %Fields = &parse_raw_result($result,$server,$tabletype); $Fields{'hostname'} = $server; # # Skip based on copyright next if (! ©right_check(\%Fields)); + + if ($area eq 'portfolio') { + next if (defined($matches{$Fields{'url'}})); + # Skip unless access control set to public or passphrase-protected + next unless (($Fields{'scope'} eq 'public') || ($Fields{'scope'} eq 'guest')); + $matches{$Fields{'url'}} = 1; + } # # Store the result in the mysql database my $result = &Apache::lonmysql::store_row($table,\%Fields); @@ -2496,12 +2626,20 @@ END delete($Server_status{$server}); } last if ($connection->aborted()); - &update_count_status($r,$hitcountsum); + if ($oldhitcountsum < $hitcountsum) { + &update_count_status($r,$hitcountsum); + if (($hitcountsum <= $env{'form.show'}) || + (!$displaycount && $hitcountsum)) { + reload_result_frame($r); + $displaycount = $hitcountsum; + } + $oldhitcountsum = $hitcountsum; + } } last if ($connection->aborted()); &update_seconds($r); } - &update_status($r,&mt('Search Complete [_1]',$server)); + &update_status($r,&mt('Search Complete on Server [_1]',$server)); &update_seconds($r); # &Apache::lonmysql::disconnect_from_db(); # This is unneccessary @@ -2509,13 +2647,13 @@ END # We have run out of time or run out of servers to talk to and # results to get, so let the client know the top frame needs to be # loaded from /adm/searchcat - $r->print("</body></html>"); -# if ($ENV{'form.catalogmode'} ne 'groupsearch') { - $r->print("<script>". - "window.location='/adm/searchcat?". - "phase=sort&". - "persistent_db_id=$ENV{'form.persistent_db_id'}';". - "</script>"); + $r->print(&Apache::loncommon::end_page()); +# if ($env{'form.catalogmode'} ne 'import') { + $r->print(<<SCRIPT); +<script> +window.location='/adm/searchcat?phase=sort&persistent_db_id=$env{'form.persistent_db_id'}'; +</script> +SCRIPT # } return; } @@ -2538,15 +2676,15 @@ sub prev_next_buttons { return '' if ($show eq 'all'); # No links if you get them all at once. # # Create buttons - my $buttons = '<input type="submit" name="prev" value="'.&mt('Prev').'" '; - $buttons .= '/>'; - $buttons .= ' 'x3; - $buttons .= '<input type="submit" name="reload" '. - 'value="'.&mt('Reload').'" />'; - $buttons .= ' 'x3; - $buttons .= '<input type="submit" name="next" value="'.&mt('Next').'" '; - $buttons .= '/>'; - return $buttons; + return '<p class="LC_nobreak">' + .'<input type="submit" name="prev" value="<"' + .' title="'.&mt('Previous').'" />' + .' ' + .'<input type="submit" name="reload" value="'.&mt('Reload').'" />' + .' ' + .'<input type="submit" name="next" value=">"' + .' title="'.&mt('Next').'" />' + .'</p>'; } ###################################################################### @@ -2563,45 +2701,61 @@ Prints the results out for selection and ###################################################################### ###################################################################### sub display_results { - my ($r,$importbutton,$closebutton,$diropendb) = @_; + my ($r,$importbutton,$closebutton,$diropendb,$area) = @_; my $connection = $r->connection; $r->print(&search_results_header($importbutton,$closebutton)); ## ## Set viewing function ## - my $viewfunction = $Views{$ENV{'form.viewselect'}}; + my $viewfunction = $Views{$env{'form.viewselect'}}; 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(); return; } ## ## $checkbox_num is a count of the number of checkboxes output on the - ## page this is used only during catalogmode=groupsearch. + ## page this is used only during catalogmode=import. my $checkbox_num = 0; ## ## Get the catalog controls setup ## my $action = "/adm/searchcat?phase=results"; ## - ## Deal with groupsearch by opening the groupsearch db file. - if ($ENV{'form.catalogmode'} eq 'groupsearch') { + ## Deal with import by opening the import db file. + if ($env{'form.catalogmode'} eq 'import') { if (! tie(%groupsearch_db,'GDBM_File',$diropendb, &GDBM_WRCREAT(),0640)) { - $r->print('Unable to store import results.</form></body></html>'); + # NOTE: this can happen when a previous request to searchcat?phase=results gets interrupted + # (%groupsearch_db is not untied) + $r->print('<p class="LC_error">'. + &mt('Unable to save import results.'). + '</p>'. + '</form>'. + &Apache::loncommon::end_page()); $r->rflush(); return; } + # untie %groupsearch_db if the connection gets aborted before the end + $r->register_cleanup(sub { + untie %groupsearch_db if (tied(%groupsearch_db)); + }); } ## ## Prepare the table for querying - my $table = $ENV{'form.table'}; + my $table = $env{'form.table'}; return if (! &ensure_db_and_table($r,$table)); ## ## Get the number of results my $total_results = &Apache::lonmysql::number_of_rows($table); 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". " of rows in table ".$table); &Apache::lonnet::logthis(&Apache::lonmysql::get_error()); @@ -2609,21 +2763,21 @@ sub display_results { } ## ## Determine how many results we need to get - $ENV{'form.start'} = 1 if (! exists($ENV{'form.start'})); - $ENV{'form.show'} = 20 if (! exists($ENV{'form.show'})); - if (exists($ENV{'form.prev'})) { - $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'}; + $env{'form.start'} = 1 if (! exists($env{'form.start'})); + $env{'form.show'} = 20 if (! exists($env{'form.show'})); + if (exists($env{'form.prev'})) { + $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; - if ($ENV{'form.show'} eq 'all') { + if ($env{'form.show'} eq 'all') { $max = $total_results ; } else { - $max = $min + $ENV{'form.show'} - 1; + $max = $min + $env{'form.show'} - 1; $max = $total_results if ($max > $total_results); } ## @@ -2631,38 +2785,150 @@ sub display_results { $r->print(&hidden_field('table'). &hidden_field('phase'). &hidden_field('persistent_db_id'). - &hidden_field('start') + &hidden_field('start'). + &hidden_field('area') ); - ## - ## Output links (if necessary) for 'prev' and 'next' pages. - $r->print - ('<table width="100%"><tr><td width="50%" align="right">'. - &prev_next_buttons($min,$ENV{'form.show'},$total_results). - '</td><td align="right">'. - &viewoptions().'</td></tr></table>' - ); + # + # 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) { - $r->print('<meta HTTP-EQUIV="Refresh" CONTENT="2">'. - '<h3>'.&mt('There are currently no results').'.</h3>'. - "</form></body></html>"); + $r->print('<p class="LC_info">'.&mt('There are currently no results.').'</p>'. + "</form>". + &Apache::loncommon::end_page()); return; } else { - $r->print - ("<center>Results $min to $max out of $total_results</center>\n"); + $r->print('<div>'. + mt('Results [_1] to [_2] out of [_3]', + $min,$max,$total_results). + "</div>\n"); } ## ## Get results from MySQL table - my @Results = &Apache::lonmysql::get_rows($table, - 'id>='.$min.' AND id<='.$max); + my $sort_command = 'id>='.$min.' AND id<='.$max; + my $order; + if (exists($env{'form.sortorder'})) { + if ($env{'form.sortorder'} eq 'asc') { + $order = 'ASC'; + } elsif ($env{'form.sortorder'} eq 'desc') { + $order = 'DESC'; + } else { + $order = ''; + } + } else { + $order = ''; + } + if ($env{'form.sortfield'} ne 'default' && + exists($sort_fields{$env{'form.sortfield'}})) { + $sort_command = $env{'form.sortfield'}.' IS NOT NULL '. + 'ORDER BY '.$env{'form.sortfield'}.' '.$order. + ' LIMIT '.($min-1).','.($max-$min+1); + } + my @Results = &Apache::lonmysql::get_rows($table,$sort_command); ## ## Loop through the results and output them. + my $tabletype = 'metadata'; + if ($area eq 'portfolio') { + $tabletype = 'portfolio_search'; + } + $r->print(&Apache::loncommon::start_data_table()); foreach my $row (@Results) { if ($connection->aborted()) { &cleanup(); return; } - my %Fields = %{&parse_row(@$row)}; - my $output="<p>\n"; + my %Fields = %{&parse_row($tabletype,@$row)}; + my $output; if (! defined($Fields{'title'}) || $Fields{'title'} eq '') { $Fields{'title'} = 'Untitled'; } @@ -2671,23 +2937,29 @@ sub display_results { # Render the result into html $output.= &$viewfunction($prefix,%Fields); # 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->print(&Apache::loncommon::end_data_table()); if (@Results < 1) { - $r->print(&mt("There were no results matching your query")); + $r->print('<p class="LC_info">' + .&mt('There were no results matching your query.') + .'</p>'); } else { - $r->print - ('<center>'. - &prev_next_buttons($min,$ENV{'form.show'},$total_results, - "table=".$ENV{'form.table'}. - "&phase=results". - "&persistent_db_id=". - $ENV{'form.persistent_db_id'}) - ."</center>\n" - ); + $r->print( + &prev_next_buttons($min,$env{'form.show'},$total_results, + "table=".$env{'form.table'}. + "&phase=results". + "&persistent_db_id=". + $env{'form.persistent_db_id'}) + ); } - $r->print("</form></body></html>"); + $r->print("</form>".&Apache::loncommon::end_page()); $r->rflush(); untie %groupsearch_db if (tied(%groupsearch_db)); return; @@ -2701,7 +2973,7 @@ sub display_results { =item &catalogmode_output($title,$url,$fnum,$checkbox_num) Returns html needed for the various catalog modes. Gets inputs from -$ENV{'form.catalogmode'}. Stores data in %groupsearch_db. +$env{'form.catalogmode'}. Stores data in %groupsearch_db. =cut @@ -2710,22 +2982,22 @@ $ENV{'form.catalogmode'}. Stores data i sub catalogmode_output { my $output = ''; my ($title,$url,$fnum,$checkbox_num) = @_; - if ($ENV{'form.catalogmode'} eq 'interactive') { + if ($env{'form.catalogmode'} eq 'interactive') { $title=~ s/\'/\\\'/g; - if ($ENV{'form.catalogmode'} eq 'interactive') { + if ($env{'form.catalogmode'} eq 'interactive') { $output.=<<END -<font size='-1'><INPUT TYPE="button" NAME="returnvalues" VALUE="SELECT" -onClick="javascript:select_data('$title','$url')"> +<font size='-1'><input type="button" name="returnvalues" value="select" +onclick="javascript:select_data('$title','$url')" /> </font> END } - } elsif ($ENV{'form.catalogmode'} eq 'groupsearch') { + } elsif ($env{'form.catalogmode'} eq 'import') { $groupsearch_db{"pre_${fnum}_link"}=$url; $groupsearch_db{"pre_${fnum}_title"}=$title; $output.=<<END; <font size='-1'> -<input type="checkbox" name="returnvalues" value="SELECT" -onClick="javascript:queue($checkbox_num,$fnum)" /> +<input type="checkbox" name="returnvalues" value="select" +onclick="javascript:queue($checkbox_num,$fnum)" /> </font> END } @@ -2745,13 +3017,13 @@ Parse a row returned from the database. ###################################################################### ###################################################################### sub parse_row { - my @Row = @_; + my ($tabletype,@Row) = @_; my %Fields; if (! scalar(@Datatypes)) { - &set_up_table_structure(); + &set_up_table_structure($tabletype); } for (my $i=0;$i<=$#Row;$i++) { - $Fields{$Datatypes[$i]->{'name'}}=&Apache::lonnet::unescape($Row[$i]); + $Fields{$Datatypes[$i]->{'name'}}=&unescape($Row[$i]); } $Fields{'language'} = &Apache::loncommon::languagedescription($Fields{'language'}); @@ -2784,12 +3056,13 @@ The 'title' field is set to "Untitled" i ########################################################### ########################################################### sub parse_raw_result { - my ($result,$hostname) = @_; + my ($result,$hostname,$tabletype) = @_; # conclude from self to others regarding fields my %Fields=&LONCAPA::lonmetadata::metadata_col_to_hash - (map { - &Apache::lonnet::unescape($_); - } (split(/\,/,$result)) ); + ($tabletype, + map { + &unescape($_); + } (split(/\,/,$result)) ); return %Fields; } @@ -2809,8 +3082,8 @@ sub handle_custom_fields { my $customshow=''; my $extrashow=''; my @customfields; - if ($ENV{'form.customshow'}) { - $customshow=$ENV{'form.customshow'}; + if ($env{'form.customshow'}) { + $customshow=$env{'form.customshow'}; $customshow=~s/[^\w\s]//g; my @fields=map { "<font color=\"#008000\">$_:</font><!-- $_ -->"; @@ -2826,7 +3099,7 @@ sub handle_custom_fields { if ($result=~/^(custom\=.*)$/) { # grab all custom metadata my $tmp=$result; $tmp=~s/^custom\=//; - my ($k,$v)=map {&Apache::lonnet::unescape($_); + my ($k,$v)=map {&unescape($_); } split(/\,/,$tmp); $customhash{$k}=$v; } @@ -2844,7 +3117,7 @@ sub handle_custom_fields { Output the proper html headers and javascript code to deal with different calling modes. -Takes most inputs directly from %ENV, except $mode. +Takes most inputs directly from %env, except $mode. =over 4 @@ -2858,7 +3131,7 @@ The following environment variables are =item 'form.catalogmode' -Checked for 'interactive' and 'groupsearch'. +Checked for 'interactive' and 'import'. =item 'form.mode' @@ -2884,15 +3157,16 @@ the name of the input field to put the t ###################################################################### sub search_results_header { my ($importbutton,$closebutton) = @_; - my $bodytag=&Apache::loncommon::bodytag(undef,undef,undef,1); - my $result = ''; + + my $js; # output beginning of search page # conditional output of script functions dependent on the mode in # which the search was invoked - if ($ENV{'form.catalogmode'} eq 'interactive'){ - if (! exists($ENV{'form.mode'}) || $ENV{'form.mode'} ne 'edit') { - $result.=<<SCRIPT; + if ($env{'form.catalogmode'} eq 'interactive'){ + if (! exists($env{'form.mode'}) || $env{'form.mode'} ne 'edit') { + $js.=<<SCRIPT; <script type="text/javascript"> +// <![CDATA[ function select_data(title,url) { changeTitle(title); changeURL(url); @@ -2908,12 +3182,13 @@ sub search_results_header { parent.opener.inf.document.forms.resinfo.elements.u.value=val; } } +// ]]> </script> SCRIPT - } elsif ($ENV{'form.mode'} eq 'edit') { - my $form = $ENV{'form.form'}; - my $element = $ENV{'form.element'}; - my $titleelement = $ENV{'form.titleelement'}; + } elsif ($env{'form.mode'} eq 'edit') { + my $form = $env{'form.form'}; + my $element = $env{'form.element'}; + my $titleelement = $env{'form.titleelement'}; my $changetitle; if (!$titleelement) { $changetitle='function changeTitle(val) {}'; @@ -2930,8 +3205,9 @@ function changeTitle(val) { END } - $result.=<<SCRIPT; + $js.=<<SCRIPT; <script type="text/javascript"> +// <![CDATA[ function select_data(title,url) { changeURL(url); changeTitle(title); @@ -2946,62 +3222,65 @@ function changeURL(val) { alert("Unable to transfer data to "+url); } } +// ]]> </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"> +// <![CDATA[ function queue(checkbox_num,val) { 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.Queue.value +='1a'+val+'b'; + parent.statusframe.document.forms.statusform.elements.acts.value +='1a'+val+'b'; } else { - parent.statusframe.document.forms.statusform.elements.Queue.value +='0a'+val+'b'; + parent.statusframe.document.forms.statusform.elements.acts.value +='0a'+val+'b'; } } else { if (document.forms.results.returnvalues.checked) { - parent.statusframe.document.forms.statusform.elements.Queue.value +='1a'+val+'b'; + parent.statusframe.document.forms.statusform.elements.acts.value +='1a'+val+'b'; } else { - parent.statusframe.document.forms.statusform.elements.Queue.value +='0a'+val+'b'; + parent.statusframe.document.forms.statusform.elements.acts.value +='0a'+val+'b'; } } } function select_group() { parent.window.location= - "/adm/groupsort?mode=$ENV{'form.mode'}&catalogmode=groupsearch&acts="+ - parent.statusframe.document.forms.statusform.elements.Queue.value; + "/adm/groupsort?mode=$env{'form.mode'}&catalogmode=import$inhibit_menu&acts="+ + parent.statusframe.document.forms.statusform.elements.acts.value; } +// ]]> +</script> +SCRIPT + + $js.=<<SCRIPT; +<script type="text/javascript"> + \$(document).ready(function() { + parent.done_loading_results(); + }); </script> SCRIPT - $result.=<<END; -</head> -$bodytag -<form name="results" method="post" action="/adm/searchcat" > -<input type="hidden" name="Queue" value="" /> + + my $start_page = &Apache::loncommon::start_page(undef,$js, + {'only_body' =>1, + 'add_wishlist' =>1, + 'add_modal' =>1}); + my $result=<<END; +$start_page +<form name="results" method="post" action="/adm/searchcat"> $importbutton END return $result; } -###################################################################### -###################################################################### -sub search_status_header { - my $bodytag=&Apache::loncommon::bodytag(undef,undef,undef,1); - return <<ENDSTATUS; -<html><head><title>Search Status</title></head> -$bodytag -<h3>Search Status</h3> -Sending search request to LON-CAPA servers.<br /> -ENDSTATUS -} - sub results_link { - my $basic_link = "/adm/searchcat?"."&table=".$ENV{'form.table'}. - "&persistent_db_id=".$ENV{'form.persistent_db_id'}; - my $results_link = $basic_link."&phase=results". - "&pause=1"."&start=1"; + my $basic_link = "/adm/searchcat?"."&table=".$env{'form.table'}. + "&persistent_db_id=".$env{'form.persistent_db_id'}; + my $results_link = $basic_link."&phase=results". + "&pause=1"."&start=1"; return $results_link; } @@ -3009,24 +3288,51 @@ sub results_link { ###################################################################### sub print_frames_interface { my $r = shift; - my $basic_link = "/adm/searchcat?"."&table=".$ENV{'form.table'}. - "&persistent_db_id=".$ENV{'form.persistent_db_id'}; - my $run_search_link = $basic_link."&phase=run_search"; + my $basic_link = "/adm/searchcat?"."&table=".$env{'form.table'}. + "&persistent_db_id=".$env{'form.persistent_db_id'}; + my $run_search_link = $basic_link."&phase=run_search"; my $results_link = &results_link(); - my $result = <<"ENDFRAMES"; -<html> -<head> -<script> + my $js = <<JS; +<script type="text/javascript"> var targetwin = opener; var queue = ''; + +var loading_results = true; +var need_reloading = false; +var new_location; +function update_results(newloc) { + if (loading_results) { + need_reloading = true; + new_location = newloc; + } else { + loading_results = true; + resultsframe.location = newloc; + } +} +function done_loading_results() { + loading_results = false; + if (need_reloading) { + need_reloading = false; + update_results(new_location); + } +} </script> -<title>LON-CAPA Digital Library Search Results</title> -</head> -<frameset rows="150,*"> +JS + + 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="resultsframe" src="$results_link"> -</frameset> -</html> +$end_page ENDFRAMES $r->print($result); @@ -3071,6 +3377,28 @@ sub evalfields { ###################################################################### ###################################################################### +sub display_tools { + my ($title, $jumpurl) = @_; + my $result; + # Metadata + $result.= + &Apache::loncommon::modal_link( + $jumpurl.'.meta?inhibitmenu=yes', + '<img class="LC_icon" src="/res/adm/pages/catalog.png" alt="Info" />', + 500,500,'_blank',undef,&mt('Metadata')); + # Stored Links + $result.= + ' <a href="javascript:;"'. + ' onclick="set_wishlistlink('."'$title','$jumpurl'".')" '. + 'title="'.&mt('Save a link for this resource in your personal Stored Links repository').'">'. + '<img class="LC_icon" src="/res/adm/pages/wishlist.png" '. + 'alt="Stored Links" style="width:22px;"/></a>'; + return $result; +} + +###################################################################### +###################################################################### + =pod =item Metadata Viewing Functions @@ -3093,12 +3421,16 @@ extra custom metadata to show. sub detailed_citation_view { my ($prefix,%values) = @_; my $result; - $result .= '<b>'.$prefix. - '<img src="'.&Apache::loncommon::icon($values{'url'}).' " />'.' '. - '<a href="http://'.$ENV{'HTTP_HOST'}.$values{'url'}.'" '. - 'target="search_preview">'.$values{'title'}."</a></b>\n"; - $result .= "<p>\n"; - $result .= '<b>'.$values{'author'}.'</b>,'. + my $jumpurl=$values{'url'}; + $jumpurl=~s|^/ext/|http://|; + $result .= + '<b>'.$prefix. + '<img src="'.&Apache::loncommon::icon($values{'url'}).'" alt="" />'.' '. + '<a href="'.$jumpurl.'?inhibitmenu=yes" '. + 'target="preview" onclick="openMyModal(this.href, 500, 500, \'yes\');return false;">'.$values{'title'}."</a></b>\n". + &display_tools($values{'title'}, $jumpurl). + "<p>\n". + '<b>'.$values{'author'}.'</b>,'. ' <i>'.$values{'owner'}.'</i><br />'; foreach my $field ( @@ -3160,25 +3492,18 @@ sub detailed_citation_view { next if (! exists($values{$field->{'name'}}) || $values{$field->{'name'}} eq ''); if (exists($field->{'type'}) && $field->{'type'} eq 'list') { - $result .= '<b>'.&mt($field->{'translate'}).'</b><ul>'; + $result .= '<b>'.&mt($field->{'translate'}).'</b>'; foreach my $item (split(',',$values{$field->{'name'}})){ - $result .= '<li>'. - '<a target="search_preview" '. - 'href="/res/'.$item.'">'.$item.'</a></li>'; + $item = &Apache::lonnet::clutter($item); + $result .= '<br />'.&display_url($item,1).'<br />'; } - $result .= '</ul>'; } 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.= - &mt($field->{'translate'}, - '<a href="'.$values{'url'}.'" '. - 'target="search_preview">'. - $values{$field->{'name'}}. - '</a>'); + $result .= '<br />'.&display_url($jumpurl,1).'<br />'; } else { $result.= &mt($field->{'translate'}, $values{$field->{'name'}}); @@ -3193,10 +3518,17 @@ sub detailed_citation_view { if (exists($values{'shortabstract'}) && $values{'shortabstract'} ne '') { $result .= '<p>'.$values{'shortabstract'}.'</p>'; } - $result .= '<hr align="left" width="200" noshade />'."\n"; return $result; } +sub detailed_citation_preview { + my ($prefix,%values)=@_; + return &detailed_citation_view($prefix,%values). + '</td><td>'. + &Apache::lonindexer::showpreview($values{'url'}); +} + + ###################################################################### ###################################################################### @@ -3210,20 +3542,42 @@ sub detailed_citation_view { sub summary_view { my ($prefix,%values) = @_; my $icon=&Apache::loncommon::icon($values{'url'}); - my $result=<<END; -$prefix<img src="$icon" /> -<a href="http://$ENV{'HTTP_HOST'}$values{'url'}" - target='search_preview'>$values{'author'}</a><br /> -$values{'title'}<br /> -$values{'owner'} -- $values{'lastrevisiondate'}<br /> + my $result=qq{$prefix<img src="$icon" alt="" />}; + if (exists($env{'form.sortfield'}) && + $env{'form.sortfield'} !~ /^(default| + author| + url| + title| + owner| + lastrevisiondate| + copyright)$/x) { + my $tmp = $values{$env{'form.sortfield'}}; + if (! defined($tmp)) { $tmp = 'undefined'; } + $result .= ' '.$tmp.' '; + } + my $jumpurl=$values{'url'}; + $jumpurl=~s|^/ext/|http://|; + my $link = '<br />'.&display_url($jumpurl,1).'<br />'; + $result .= + '<a href="'.$jumpurl.'?inhibitmenu=yes"'. + ' target="preview" onclick="openMyModal(this.href, 500, 500, \'yes\');return false;">'.$values{'title'}.'</a>'. + &display_tools($values{'title'}, $jumpurl).<<END; +<br /> +$link<br /> +$values{'author'}, $values{'owner'} -- $values{'lastrevisiondate'}<br /> $values{'copyrighttag'}<br /> $values{'extrashow'} -</p> -<hr align='left' width='200' noshade /> END return $result; } +sub summary_preview { + my ($prefix,%values)=@_; + return &summary_view($prefix,%values). + '</td><td>'. + &Apache::lonindexer::showpreview($values{'url'}); +} + ###################################################################### ###################################################################### @@ -3237,14 +3591,51 @@ END ###################################################################### sub compact_view { my ($prefix,%values) = @_; + my $jumpurl=$values{'url'}; + $jumpurl=~s|^/ext/|http://|; + + my $link = &display_url($jumpurl,1); + my $result = - $prefix.'<img src="'.&Apache::loncommon::icon($values{'url'}). - '"> <a href="'.$values{'url'}.'" target="search_preview">'. - $values{'title'}.'</a>'.(' 'x2). - '<b>'.$values{'author'}.'</b><br />'; + $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 .= ' '.$tmp.' '; + } + $jumpurl = &HTML::Entities::encode($jumpurl,'<>&"'); + $result.=' <span class="LC_nobreak">'. + '<a href="'.$jumpurl.'?inhibitmenu=yes" target="preview" onclick="openMyModal(this.href, 500, 500, \'yes\');return false;">'. + &HTML::Entities::encode($values{'title'},'<>&"').'</a></span> '. + &display_tools($values{'title'}, $jumpurl). + $link.' <b>'.$values{'author'}.'</b> ('.$values{'domain'}.')'; 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 { + # replace the links to open in a new window + # (because the search opens in a new window, it gets + # confusing when the links open a tab in the + # parent window; ideally we should not force windows) + my $onclick = " onclick=\"window.open(this.href, '_blank', 'toolbar=1,location=1,menubar=0');return false;\""; + $link=&Apache::lonhtmlcommon::crumbs( + $url, + 'preview', + '', + '', + $skiplast,$onclick).' '; + } + return $link; +} ###################################################################### ###################################################################### @@ -3261,14 +3652,20 @@ sub fielded_format_view { 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; -$prefix <img src="$icon" /> +$prefix <img src="$icon" alt="" /> <dl> <dt>URL:</dt> - <dd><a href="http://$ENV{'HTTP_HOST'}$values{'url'}" - target='search_preview'>$values{'url'}</a></dd> + <dd><a href="$jumpurl?inhibitmenu=yes" + target='preview'>$values{'url'}</a> END - foreach my $field ('title','author','subject','keywords','notes', + $result .= + &display_tools($values{'title'}, $jumpurl).' + </dd>'; + foreach my $field ('title','author','domain','subject','keywords','notes', 'mimetag','language','creationdate','lastrevisiondate', 'owner','copyrighttag','hostname','abstract') { $result .= (' 'x4).'<dt>'.$Translated{$field}.'</dt>'."\n". @@ -3288,7 +3685,6 @@ END } $result .= "</dl>\n"; $result .= $values{'extrashow'}; - $result .= '<hr align="left" width="200" noshade />'."\n"; return $result; } @@ -3309,7 +3705,7 @@ sub xml_sgml_view { my ($prefix,%values) = @_; my $xml = '<LonCapaResource>'."\n"; # The usual suspects - foreach my $field ('url','title','author','subject','keywords','notes') { + foreach my $field ('url','title','author','subject','keywords','notes','domain') { $xml .= qq{<$field>$values{$field}</$field>}."\n"; } # @@ -3362,7 +3758,6 @@ $prefix $xml </pre> $values{'extrashow'} -<hr align='left' width='200' noshade /> END return $result; } @@ -3402,33 +3797,32 @@ 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 <i>[_1]</i>. Please modify your search.',$ENV{'form.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 <b>[_1]</b>:<i>[_2]</i>.',$field,$ENV{'form.'.$field}); + $errorstring = &mt('Unable to understand the search phrase [_1]: [_2]' + ,'<i>'.$field.'</i>' + ,$env{'form.'.$field}); } - my $bodytag = &Apache::loncommon::bodytag('Search'); 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); -<html> -<head> -<title>The LearningOnline Network with CAPA</title> -</head> -$bodytag +$start_page <form method="post" action="/adm/searchcat"> $hidden_fields $closebutton <hr /> <h2>$heading</h2> -<p> +<p class="LC_warning"> $errorstring </p> <p> -<a href="/adm/searchcat?$parms&persistent_db_id=$ENV{'form.persistent_db_id'}">$revise</a> +<a href="/adm/searchcat?$parms&persistent_db_id=$env{'form.persistent_db_id'}">$revise</a> </p> -</body> -</html> +$end_page ENDPAGE } @@ -3454,29 +3848,34 @@ $parms is extra information to include i ###################################################################### sub output_blank_field_error { my ($r,$closebutton,$parms,$hidden_fields)=@_; - my $bodytag=&Apache::loncommon::bodytag('Search'); - my $errormsg = &mt('You did not fill in enough information for the search to be started. You need to fill in relevant fields on the search page in order for a query to be processed.'); + my $errormsg = &mt('You did not fill in enough information for the search to be started. You need to fill in relevant fields on the search page in order for a query to be processed.'); my $revise = &mt('Revise Search Request'); - my $heading = &mt('Unactionable Search Queary'); + my $heading = &mt('Unactionable Search Query'); + my $start_page = &Apache::loncommon::start_page('Search'); + my $end_page = &Apache::loncommon::end_page(); + if ($closebutton) { + $closebutton = '<p>'.$closebutton.'</p><hr />'; + } else { + &Apache::lonhtmlcommon::add_breadcrumb + ({href=>'', + text=>$heading,}); + $start_page .= &Apache::lonhtmlcommon::breadcrumbs(); + } + $r->print(<<ENDPAGE); -<html> -<head> -<title>The LearningOnline Network with CAPA</title> -</head> -$bodytag +$start_page <form method="post" action="/adm/searchcat"> $hidden_fields $closebutton -<hr /> +</form> <h2>$heading</h2> -<p> +<p class="LC_warning"> $errormsg </p> <p> -<a href="/adm/searchcat?$parms&persistent_db_id=$ENV{'form.persistent_db_id'}">$revise</a> +<a href="/adm/searchcat?$parms&persistent_db_id=$env{'form.persistent_db_id'}">$revise</a> </p> -</body> -</html> +$end_page ENDPAGE return; } @@ -3503,27 +3902,23 @@ Inputs: sub output_date_error { my ($r,$message,$closebutton,$hidden_fields)=@_; # make query information persistent to allow for subsequent revision - my $bodytag=&Apache::loncommon::bodytag(undef,undef,undef,1); + my $start_page = &Apache::loncommon::start_page('Search'); + my $end_page = &Apache::loncommon::end_page(); + my $heading = &mt('Error'); $r->print(<<RESULTS); -<html> -<head> -<title>The LearningOnline Network with CAPA</title> -</head> -$bodytag -<img align='right' src='/adm/lonIcons/lonlogos.gif' /> -<h1>Search Catalog</h1> +$start_page <form method="post" action="/adm/searchcat"> $hidden_fields <input type='button' value='Revise search request' -onClick='this.form.submit();' /> +onclick='this.form.submit();' /> $closebutton +</form> <hr /> -<h3>Error</h3> -<p> +<h3>$heading</h3> +<p class="LC_error"> $message </p> -</body> -</html> +$end_page RESULTS } @@ -3543,7 +3938,7 @@ Cleans the global %groupsearch_db by rem ###################################################################### sub start_fresh_session { delete $groupsearch_db{'mode_catalog'}; - foreach (keys %groupsearch_db) { + foreach (keys(%groupsearch_db)) { if ($_ =~ /^pre_/) { delete $groupsearch_db{$_}; } @@ -3561,8 +3956,8 @@ sub cleanup { &Apache::lonnet::logthis('Failed cleanup searchcat: groupsearch_db'); } } - &untiehash(); &Apache::lonmysql::disconnect_from_db(); + return OK; } __END__