package HTML::Highlighter;
use strict;
use warnings;
use HTML::Parser;
use Plack::Request;
use Plack::Util::Accessor qw/param callback/;
use List::Util qw/first/;
use parent 'Plack::Middleware';
use 5.008_001;
our $VERSION = "0.05";
$VERSION = eval $VERSION;
sub call {
my ($self, $env) = @_;
my $res = $self->app->($env);
$self->response_cb( $res, sub {
my $res = shift;
my $h = Plack::Util::headers($res->[1]);
my $type = $h->get("Content-Type");
return $res unless $type and $type =~ /html/i;
$self->callback->($env) if $self->callback;
my $req = Plack::Request->new($env);
$self->param("") unless defined $self->param;
my $highlights = do {
if ($env->{'psgix.highlight'}) {
$env->{'psgix.highlight'};
} else {
my $param = first {$req->parameters->{$_}} ($self->param, qw/q query search highlight/);
$param ? $req->parameters->{$param} : undef;
}
};
return $res unless $highlights;
my @highlights = split /\s+/, $highlights;
my $html;
my $p = HTML::Parser->new(
api_version => 3,
handlers => {
default => [
sub {
$html .= $_[0]
}, "text"
],
text => [
sub {
for my $highlight (@highlights) {
$_[0] =~ s/(\Q$highlight\E)/$1<\/span>/gi;
}
$html .= $_[0]
}, "text"
],
end_document => [
sub {
$res->[2] = [$html];
$h->set('Content-Length' => length $html)
}
],
}
);
my $done;
return sub {
my $chunk = shift;
return if $done;
if (defined $chunk) {
$p->parse($chunk);
return '';
} else {
$p->eof;
$done = 1;
return $html;
}
};
});
}
1;
__END__
=head1 NAME
HTML::Highlighter - PSGI middleware to highlight text in an HTML response
=head1 SYNOPSIS
use Plack::Builder;
use HTML::Highlighter;
# highlight the "search" query param
builder {
enable "+HTML::Highlighter", param => "search";
...
$app;
};
# or highlight the user stored in session
builder {
enable "+HTML::Highlighter", callback => sub {
my $env = shift;
$env->{'psgix.highlight'} = $env->{'psgix.session'}{user};
};
...
$app;
};
=head1 DESCRIPTION
The C module is a piece of PSGI middleware that
will inspect an HTML response and highlight parts of the page based
on a query parameter or other request data. This is very much like
what Google does when you load a page from their cache. Any text
that matches your original query is highlighted.
[matching text]
If no param or callback are provided to C, it
will look for commonly used search parameters (e.g. q, query, search,
and highlight.)
This module also includes a javascript file called highlighter.js
which gives you a class with methods to jump (scroll) through the
highlights.
=head1 CONSTRUCTOR PARAMETERS
=over
=item B
This option allows you to specify a query parameter to be used for
the highlighting. For example, if you specify "search" as the param,
each response will look for a query parameter called "search" will
highlight that value in the response.
=item B
This option lets you specify a function that will be called on each
request to generate the text used for highlighting. The function
will be passed the $env hashref, and should set 'psgix.highlight'
on it. This value will be used for the highlighting. This could be
useful if you want to highlight a username that is stored in a
session, or something similar.
=back
=head1 SEE ALSO
L
L
=head1 COPYRIGHT AND LICENSE
Copyright (C) 2010 Lee Aylward , all rights reserved.
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=head1 AUTHOR
Lee Aylward,
=cut