This is used in
OddMuse, a
UseMod 0.92 descendant, based on
WikiPatches/BetterSearchOutput.
The #FILE stuff can safely be removed; it relates to
OddMuse's file upload feature where the uploaded files are stored in pages. This is why they have to be excluded, normally.
See the Oddmuse manual for more.
[1]
sub SearchTitleAndBody {
my $string = shift;
my $and = T('and');
my $or = T('or');
my @strings = split(/ +$and +/, $string);
my @found;
foreach my $name (AllPagesList()) {
OpenPage($name);
OpenDefaultText();
next if ($Text{'text'} =~ /^#FILE / and $string !~ /^\^#FILE/); # skip files unless requested
my $found = 1; # assume found
foreach my $str (@strings) {
my @temp = split(/ +$or +/, $str);
$str = join('|', @temp);
if (not ($Text{'text'} =~ /$str/i)) {
$found = 0;
last;
}
}
if ($found or $name =~ /$string/i) {
push(@found, $name);
} elsif ($FreeLinks && ($name =~ m/_/)) {
my $freeName = $name;
$freeName =~ s/_/ /g;
if ($freeName =~ /$string/i) {
push(@found, $name);
}
}
}
return @found;
}
sub PrintSearchResults {
my ($searchstring, @results) = @_ ;
my $and = T('and');
my $or = T('or');
my $searchstring = join('|', split(/ +(?:$and|$or) +/, $searchstring));
my ($snippetlen, $maxsnippets) = (100, 4) ; # these seem nice.
print $q->h2(Ts('%s pages found:', ($#results + 1)));
my $files = ($searchstring =~ /^\^#FILE/); # usually skip files
foreach my $name (@results) {
OpenPage($name);
OpenDefaultText();
my $pageText = QuoteHtml($Text{'text'});
# get the page, filter it, remove all tags
$pageText =~ s/$FS//g; # Remove separators (paranoia)
$pageText =~ s/[\s]+/ /g; # Shrink whitespace
$pageText =~ s/([-_=\\*\\.]){10,}/$1$1$1$1$1/g ; # e.g. shrink "----------"
my $htmlre = join('|',(@HtmlTags, 'pre', 'nowiki', 'code'));
$pageText =~ s/\<\/?($htmlre)(\s[^<>]+?)?\>//gi;
# entry header
print '<p>' . $q->span({-class=>'result'}, GetPageLink($name)), $q->br();
if ($files) {
$pageText =~ /^#FILE ([^ ]+)/;
print $1;
} else {
# show a snippet from the top of the document
my $j = index($pageText, ' ', $snippetlen); # end on word boundary
my $t = substr($pageText, 0, $j);
$t =~ s/($searchstring)/<strong>\1<\/strong>/gi;
print $t, ' ', $q->b('...');
$pageText = substr($pageText, $j); # to avoid rematching
# search for occurrences of searchstring
my $jsnippet = 0 ;
while ($jsnippet < $maxsnippets && $pageText =~ m/($searchstring)/i) {
$jsnippet++;
if (($j = index($pageText, $1)) > -1 ) {
# get substr containing (start of) match, ending on word boundaries
my $start = index($pageText, ' ', $j-($snippetlen/2));
$start = 0 if ($start == -1);
my $end = index($pageText, ' ', $j+($snippetlen/2));
$end = length($pageText ) if ($end == -1);
$t = substr($pageText, $start, $end-$start);
# highlight occurrences and tack on to output stream.
$t =~ s/($searchstring)/<strong>\1<\/strong>/gi;
print $t, ' ', $q->b('...');
# truncate text to avoid rematching the same string.
$pageText = substr($pageText, $end);
}
}
}
# entry trailer
print $q->br(), $q->span({-class=>'info'},
int((length($pageText)/1024)+1) . 'K - ' . T('last updated') . ' '
. TimeToText($Section{ts}) . ' ' . T('by') . ' '
. GetAuthorLink($Section{'host'}, $Section{'username'})), '</p>';
}
}