Changeset 401
- Timestamp:
- 06/13/04 15:07:18 (5 years ago)
- Location:
- trunk
- Files:
-
- 1 added
- 9 modified
-
Build.PL (modified) (1 diff)
-
Changes (modified) (1 diff)
-
MANIFEST (modified) (1 diff)
-
PREREQUISITES (modified) (1 diff)
-
lib/OpenGuides.pm (modified) (3 diffs)
-
lib/OpenGuides/SuperSearch.pm (modified) (12 diffs)
-
t/33_supersearch_advanced_search.t (added)
-
templates/navbar.tt (modified) (1 diff)
-
templates/supersearch.tt (modified) (2 diffs)
-
wiki.cgi (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Build.PL
r395 r401 229 229 'CGI::Wiki::Plugin::Diff' => 0, 230 230 'CGI::Wiki::Plugin::GeoCache' => 0, 231 'CGI::Wiki::Plugin::Locator::UK' => '0.0 6',231 'CGI::Wiki::Plugin::Locator::UK' => '0.09', 232 232 'CGI::Wiki::Plugin::RSS::ModWiki' => '0.02', 233 233 'CGI::Wiki::Plugin::RSS::Reader' => '1.3', # earlier versions don't support RSS 2.0 -
trunk/Changes
r390 r401 6 6 links being displayed for nodes with no address data (spotted 7 7 by Steve Jolly). 8 Remove inline style from recent_changes.tt. You will need to add8 Removed inline style from recent_changes.tt. You will need to add 9 9 the styles table#recentchanges, td.recentchanges_meta, 10 10 td.recentchanges_user, td.recentchanges_node_name and 11 11 td.recentchanges_comment to your stylesheets. 12 Added searching by distance from an arbitrary point (click on 13 Advanced Search). 14 Internal rejigging - extracted some methods from wiki.cgi to 15 OpenGuides.pm. 12 16 13 17 0.32 7 June 2004 -
trunk/MANIFEST
r392 r401 56 56 t/31_supersearch.t 57 57 t/32_supersearch_simple_metadata.t 58 t/33_supersearch_advanced_search.t 58 59 t/41_deletion.t 59 60 t/51_display_node.t -
trunk/PREREQUISITES
r361 r401 11 11 CGI::Wiki::Plugin::Diff 12 12 CGI::Wiki::Plugin::GeoCache 13 CGI::Wiki::Plugin::Locator::UK (version 0.0 6or later)13 CGI::Wiki::Plugin::Locator::UK (version 0.09 or later) 14 14 CGI::Wiki::Plugin::RSS::ModWiki (version 0.02 or later) 15 15 CGI::Wiki::Plugin::RSS::Reader (version 1.3 or later) -
trunk/lib/OpenGuides.pm
r400 r401 13 13 use vars qw( $VERSION ); 14 14 15 $VERSION = '0.33_0 5';15 $VERSION = '0.33_06'; 16 16 17 17 =head1 NAME … … 303 303 my $metres = $args{metres}; 304 304 my $formatter = $self->wiki->formatter; 305 306 305 my @finds = $self->locator->find_within_distance( 307 306 node => $node, … … 333 332 id => "index", # KLUDGE 334 333 template => "site_index.tt", 335 vars=> \%tt_vars,334 tt_vars => \%tt_vars, 336 335 ); 337 336 } -
trunk/lib/OpenGuides/SuperSearch.pm
r341 r401 1 1 package OpenGuides::SuperSearch; 2 2 use strict; 3 our $VERSION = '0.0 4';3 our $VERSION = '0.05'; 4 4 5 5 use CGI qw( :standard ); 6 use CGI::Wiki::Plugin::Locator::UK; 6 7 use File::Spec::Functions qw(:ALL); 7 8 use OpenGuides::Template; … … 53 54 $self->{css} = $config->{_}{stylesheet_url}; 54 55 $self->{head} = $config->{_}{site_name} . " Search"; 56 57 my $locator = CGI::Wiki::Plugin::Locator::UK->new; 58 $wiki->register_plugin( plugin => $locator ); 59 $self->{locator} = $locator; 55 60 56 61 return $self; … … 92 97 $tt_vars{ss_info_url} = 'http://london.openguides.org/?Search_Script'; 93 98 99 # Strip out any non-digits from dist; lat and long also allowed '-' and '.' 100 $vars{lat} =~ s/[^-\.0-9]//g; 101 $vars{long} =~ s/[^-\.0-9]//g; 102 $vars{distance_in_metres} =~ s/[^0-9]//g; 103 94 104 # Do we have an existing search? if so, do it. 95 if ( $vars{search} ) { 105 my $doing_search; 106 if ( $vars{search} 107 or ( defined $vars{lat} 108 && defined $vars{long} 109 && defined $vars{distance_in_metres} ) 110 ) { 111 $doing_search = 1; 96 112 $tt_vars{search_terms} = $vars{search}; 113 $tt_vars{lat} = $vars{lat}; 114 $tt_vars{long} = $vars{long}; 115 $tt_vars{dist} = $vars{distance_in_metres}; 97 116 $self->_perform_search( vars => \%vars ); 98 117 } … … 100 119 if ( $self->{error} ) { 101 120 $tt_vars{error_message} = $self->{error}; 102 } elsif ( $ vars{search}) {103 my %results =%{ $self->{results} || {} };104 my $numres = scalar keys %results;121 } elsif ( $doing_search ) { 122 my @results = values %{ $self->{results} || {} }; 123 my $numres = scalar @results; 105 124 106 125 # For 0 or many we display results, for 1 we redirect to that page. 107 126 if ( $numres == 1 && !$self->{return_tt_vars}) { 108 my ($node) = each %results;127 my $node = $results[0]{name}; 109 128 my $output = CGI::redirect( $self->{wikimain} . "?" 110 129 . CGI::escape($node) ); … … 127 146 } 128 147 129 # Sort the results - first index of array in HoA is the score. 130 my @res_selected = sort 131 { $results{$b}[0] <=> $results{$a}[0] } 132 keys %results; 148 # Sort the results - by distance if we're searching on that 149 # or by score otherwise. 150 if ( $vars{distance_in_metres} ) { 151 @results = sort { $a->{distance} <=> $b->{distance} } @results; 152 } else { 153 @results = sort { $a->{score} <=> $b->{score} } @results; 154 } 133 155 134 156 # Now snip out just the ones for this page. The -1 is … … 136 158 my $from = $tt_vars{first_num} ? $tt_vars{first_num} - 1 : 0; 137 159 my $to = $tt_vars{last_num} - 1; # kludge to empty arr for no res 138 @res_selected = @res_selected[ $from .. $to ]; 139 140 my @result_urls; 141 foreach ( @res_selected ) { 142 my @summary = grep { defined $_ } @{$results{$_}}[1 .. 6]; 143 push @result_urls, 144 { 145 name => $_, 146 url => $self->{wikimain} . "?" . CGI::escape($_), 147 summary => join "\n", @summary, 148 }; 149 } 150 $tt_vars{results} = \@result_urls; 160 @results = @results[ $from .. $to ]; 161 162 $tt_vars{results} = \@results; 151 163 } 152 164 } … … 262 274 my ($self, %args) = @_; 263 275 my %vars = %{ $args{vars} || {} }; 276 264 277 my $srh = $vars{search}; 265 278 266 # Check for only valid characters in tainted search param 267 # (quoted literals are OK, as they are escaped) 268 if ( $srh !~ /^("[^"]*"|[\w \-',()!*%\[\]])+$/i) { #" 269 $self->{error} = "Search expression contains invalid character(s)"; 270 return; 271 } 272 273 $self->_build_parser && exists($self->{error}) && return; 274 $self->_apply_parser($srh); 279 # Perform text search if search terms entered, otherwise collect up 280 # all nodes to check distance. 281 if ( $srh ) { 282 # Check for only valid characters in tainted search param 283 # (quoted literals are OK, as they are escaped) 284 if ( $srh !~ /^("[^"]*"|[\w \-',()!*%\[\]])+$/i) { #" 285 $self->{error} = "Search expression contains invalid character(s)"; 286 return; 287 } 288 $self->_build_parser && exists($self->{error}) && return; 289 $self->_apply_parser($srh); 290 } else { 291 my @all_nodes = $self->{wiki}->list_all_nodes; 292 my $formatter = $self->{wiki}->formatter; 293 my %results = map { 294 my $name = $formatter->node_name_to_node_param( $_ ); 295 $name => { 296 name => $name, 297 score => 0, 298 summary => "FIXME", 299 } 300 } @all_nodes; 301 $self->{results} = \%results; 302 } 303 304 # Now filter by distance if required. 305 my ($lat, $long, $dist) = @vars{ qw( lat long distance_in_metres ) }; 306 if ( defined $lat && defined $long && $dist ) { 307 my %results = %{ $self->{results} || {} }; 308 my @close = $self->{locator}->find_within_distance( 309 lat => $lat, 310 long => $long, 311 metres => $dist, 312 ); 313 my %close_hash = map { $_ => 1 } @close; 314 my @nodes = keys %results; 315 foreach my $node ( @nodes ) { 316 my $unmunged = $node; # KLUDGE 317 $unmunged =~ s/_/ /g; 318 if ( exists $close_hash{$unmunged} ) { 319 my $distance = $self->{locator}->distance( 320 from_lat => $lat, 321 from_long => $long, 322 to_node => $unmunged, 323 unit => "metres" 324 ); 325 $results{$node}{distance} = $distance; 326 } else { 327 delete $results{$node}; 328 } 329 } 330 $self->{results} = \%results; 331 } 275 332 } 276 333 … … 341 398 my $op = shift @tree_arr; 342 399 my $meth = 'matched_'.$op; 343 344 400 return $self->can($meth) ? $self->$meth(@tree_arr) : undef; 345 401 } … … 382 438 383 439 sub matched_AND { 384 my $self = shift; 385 386 # Do all the searches 387 my @comby_res = map { 388 my %match_hash = $self->_matched_items(tree => $_); 389 \%match_hash 390 } @_; 391 392 # Use the first one's results as a basis for the output hash 393 my @out = keys %{$comby_res[0]}; 394 my %out; 395 396 # Zap out any entries which do not appear in one of the other searches. 397 PAGE: 398 for my $page (@out) { 399 for (@comby_res[1..$#comby_res]) { 400 (delete $out{$page}),next PAGE if !exists $_->{$page}; 401 } 402 403 $out{$page} = $self->intersperse($page, @comby_res); 404 } 405 406 return %out; 440 my ($self, @subsearches) = @_; 441 442 # Do the first subsearch. 443 my %results = $self->_matched_items( tree => $subsearches[0] ); 444 445 # Now do the rest one at a time and remove from the results anything 446 # that doesn't come up in each subsearch. Results that survive will 447 # have a score that's the sum of their score in each subsearch. 448 foreach my $tree ( @subsearches[ 1 .. $#subsearches ] ) { 449 my %subres = $self->_matched_items( tree => $tree ); 450 my @pages = keys %results; 451 foreach my $page ( @pages ) { 452 if ( exists $subres{$page} ) { 453 $results{$page}{score} += $subres{$page}; 454 } else { 455 delete $results{$page}; 456 } 457 } 458 } 459 460 return %results; 407 461 } 408 462 … … 420 474 421 475 sub matched_OR { 422 my $self = shift;423 424 # Do all the searches 425 my @list_res = map {426 my %match_hash = $self->_matched_items(tree => $_);427 \%match_hash428 } @_;429 430 # Apply union of hashes, merging any duplicates.431 my %union;432 for (@list_res){433 while (my ($k,$v) = each %$_) {434 $union{$k}++;476 my ($self, @subsearches) = @_; 477 478 # Do all the searches. Results will have a score that's the sum 479 # of their score in each subsearch. 480 my %results; 481 foreach my $tree ( @subsearches ) { 482 my %subres = $self->_matched_items( tree => $tree ); 483 foreach my $page ( keys %subres ) { 484 if ( $results{$page} ) { 485 $results{$page}{score} += $subres{$page}{score}; 486 } else { 487 $results{$page} = $subres{$page}; 488 } 435 489 } 436 490 } 437 438 my %out; 439 440 $out{$_} = $self->intersperse($_, @list_res) for keys %union; 441 442 return %out; 443 } 444 491 return %results; 492 } 445 493 446 494 =item B<NOT searches> … … 513 561 # context either side. 514 562 my $wexp = qr/\b.{0,60}\b$wmatch\b.{0,60}\b/is; 515 my %res ;563 my %results; 516 564 517 565 # Search every wiki page for matches … … 528 576 $temp =~ s/_/ /g; 529 577 530 # Compute score and prepend to array of matches531 my $score = @out;578 # Compute score and create summary. 579 my $score = scalar @out; 532 580 $score +=10 if $temp =~ /$wexp/; 533 $res{$k} = unshift(@out,$score) && \@out if @out; 534 } 535 536 return %res; 581 $results{$k} = { 582 score => $score, 583 summary => join( "", @out ), 584 name => $k, 585 } 586 if $score; 587 } 588 589 return %results; 537 590 } 538 591 -
trunk/templates/navbar.tt
r397 r401 38 38 </form> 39 39 </div> 40 <div class="navbar_item"> 41 <a href="supersearch.cgi">Advanced Search</a> 42 </div> 40 43 </div> 41 44 -
trunk/templates/supersearch.tt
r343 r401 24 24 25 25 <form method="get" action="supersearch.cgi"> 26 <label for="search_upper">Search :</label>26 <label for="search_upper">Search text:</label> 27 27 <input type="text" name="search" value="[% search_terms %]" size="50" maxlength="80" id="search_upper" value="Search text" onclick="this.value=''" /> 28 <br /> 29 Located within 30 <input type="text" name="distance_in_metres" value="[% dist %]" size="4" maxlength="4" /> 31 metres of 32 latitude <input type="text" name="lat" value="[% lat %]" size="10" maxlength="10" /> 33 longitude <input type="text" name="long" value="[% long %]" size="10" maxlength="10" /> 34 <br /> 28 35 <input type="submit" name="go" class="form_button" value="Go" /> 29 36 </form> … … 38 45 [% FOREACH result = results %] 39 46 <li> 40 <a href="[% result.url %]"><b>[% result.name.replace('_', ' ') %]</b></a> 47 <a href="[% full_cgi_url %]?[% result.name %]"><b>[% result.name.replace('_', ' ') %]</b></a> 48 [% IF result.distance %] 49 ([% result.distance %] metres away) 50 [% END %] 41 51 <br /> 42 52 [% result.summary %] -
trunk/wiki.cgi
r393 r401 5 5 6 6 use vars qw( $VERSION ); 7 $VERSION = '0.33_0 5';7 $VERSION = '0.33_06'; 8 8 9 9 use CGI qw/:standard/;
