I've written a module for implementing the backend of a Google suggest-like autocompletion system, and I would like to upload it to CPAN. I'm not so sure about the name. I've been working with the "AutoComplete" name, but I know that people usually complain about top-level namespaces, etc.
The full code is here for your enjoyment.
Update: I have thought about something like (WWW|HTML|JavaScript)::Form::AutoComplete::BackEnd, but since the back-end is independent of the front-end, it is not limited to HTML forms, or to the WWW, or to JavaScript clients...
Update2: I have figured a use for $prefix; I'll update the POD before releasing the module.
Update3: The use that I have found for $prefix is the following: if $prefix = [], you get the drop-down list of options but the word in the input box is not completed; if $prefix = [''], the word is completed and the completed part is selected (that's the value used by Google suggest). I haven't investigated other values yet.
package AutoComplete; $VERSION = '0.10'; use strict; use warnings; =head1 NAME AutoComplete - Google Suggest-compatible autocompletion backend =head1 SYNOPSYS package MyAC; use CGI; use base qw(AutoComplete); my @NAMES = qw(alice bob charlie); MyAC->run; sub expand { my ($self, $query) = @_; # do something to expand the query my $re = qr/^\Q$query\E/i; my @names = grep /$re/, @NAMES; (lc $query, \@names, [], []); } =head1 DESCRIPTION This is a base class for implementing an autocomplete server with the +same protocol used by Google Suggest ( http://www.google.com/webhp?complete +=1&hl=en ). The front-end JavaScript code is discussed in http://serversideguy.blogspot.com/2004/12/google-suggest-dissected.htm +l . This module is used by creating a subclass, which should override the C<expand> method, which takes care of searching for the autocompletion + results. =head1 METHODS =over =item $class->run(%args) Run the whole autocompletion process in one fell swoop. Prints everyth +ing to standard output, including the HTTP headers. The arguments %args are p +assed to the constructor. =cut sub run { my $class = shift; my $self = $class->new(@_); print $self->header; print($self->no_js), return unless $self->param('js'); my ($query, $names, $values, $prefix) = $self->expand($self->query +); print $self->output($query, $names, $values, $prefix); } =item $class->new(%args) Create a new AutoComplete object. Currently the only argument is C<cgi +>, which should provide a L<CGI> or CGI-compatible object. If none is provided, + a new CGI object is created by default. =cut sub new { my ($class, %args) = @_; my $cgi = $args{cgi} || CGI->new; bless { cgi => $cgi, }, shift; } =item $obj->query Returns the string to be expanded. =cut sub query { shift->param('qu'); } =item $obj->cgi Returns the CGI object being used. =cut sub cgi { shift->{cgi} } =item $obj->param($name) Get a CGI parameter. Just delegates the call to $self->cgi. =cut sub param { shift->cgi->param(@_) } =item $obj->header(%args) Return the HTTP headers. By default delegates to $self->cgi, but it us +es the UTF-8 encoding by default. =cut sub header { shift->cgi->header( -charset => 'utf-8', @_ ) } =item $obj->output($query, $names, $values, $prefix) Converts the expanded values into JavaScript, as expected by the calli +ng frontend script. $query is a string; all the other parameters are arra +y refs. =cut sub output { my ($self, $query, $names, $values, $prefix) = @_; my $ret = qq{sendRPCDone(frameElement, "$query", }; $ret .= $self->as_array($names). ", "; $ret .= $self->as_array($values). ", "; $ret .= $self->as_array($prefix). ");\n"; $ret; } =item $obj->expand($query) Provide the autocompleted values for the query. Returns a 4-element li +st: ($query, $names, $values, $prefix). $query is the query as returned to + the frontend script (typically converted to lowercase). $names is an array + ref of results. $values is an array ref of values that are usually shown o +n the right-hand side of the drop-down box in the front end; it is used by G +oogle for the estimated result count. The purpose of $prefix is not certain +at this time. =cut sub expand { my ($self, $query) = @_; (lc $query, [],[],[]); } =item $obj->as_array(\@arr) Convert an array ref into a JavaScript Array constructor. Returns a st +ring. =cut sub as_array { my ($self, $a) = @_; 'new Array(' . join(", ", map { qq("$_") } @$a) . ')'; } =item $obj->no_js Returns that message that is returned by the Google backend when the C +<js> CGI parameter is not true. =cut sub no_js { print <<HTML; <html> <head> <meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> <script> function bodyLoad() { if (parent == window) return; var frameElement = this.frameElement; parent.sendRPCDone(frameElement, "", new Array(), new Array(), new A +rray("")); } </script></head><body onload='bodyLoad();'></body></html> HTML exit; } =back =head1 SEE ALSO http://www.google.com/webhp?complete=1&hl=en http://serversideguy.blogspot.com/2004/12/google-suggest-dissected.htm +l =head1 AUTHOR Ivan Tubert-Brohman E<lt>itub@cpan.orgE<gt> =head1 COPYRIGHT Copyright (c) 2004 Ivan Tubert-Brohman. All rights reserved. This prog +ram is free software; you can redistribute it and/or modify it under the same + terms as Perl itself. The original JavaScript frontend code is Copyright (c) 2004 Google, In +c. Use it at your own risk or write or find a free version. =cut 1;
|
---|