line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package JavaScript::Autocomplete::Backend; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
$VERSION = '0.10'; |
4
|
|
|
|
|
|
|
|
5
|
2
|
|
|
2
|
|
86798
|
use strict; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
86
|
|
6
|
2
|
|
|
2
|
|
12
|
use warnings; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
2652
|
|
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
=head1 NAME |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
JavaScript::Autocomplete::Backend - Google Suggest-compatible autocompletion |
11
|
|
|
|
|
|
|
backend |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
=head1 SYNOPSYS |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
package MyAutocompleter; |
16
|
|
|
|
|
|
|
use base qw(JavaScript::Autocomplete::Backend); |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
my @NAMES = qw(alice bob charlie); |
19
|
|
|
|
|
|
|
sub expand { |
20
|
|
|
|
|
|
|
my ($self, $query) = @_; |
21
|
|
|
|
|
|
|
# do something to expand the query |
22
|
|
|
|
|
|
|
my $re = qr/^\Q$query\E/i; |
23
|
|
|
|
|
|
|
my @names = grep /$re/, @NAMES; |
24
|
|
|
|
|
|
|
(lc $query, \@names, [], [""]); |
25
|
|
|
|
|
|
|
} |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
MyAutocompleter->run; |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
=head1 DESCRIPTION |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
This is a base class for implementing an autocompletion server with the same |
32
|
|
|
|
|
|
|
protocol used by Google Suggest ( http://www.google.com/webhp?complete=1&hl=en |
33
|
|
|
|
|
|
|
). It is basically a CGI script that takes a word to be completed as the "qu" |
34
|
|
|
|
|
|
|
parameter and returns a specially concoted JavaScript statement. For more |
35
|
|
|
|
|
|
|
efficiency it should be possible to turn it into a mod_perl handler; that is |
36
|
|
|
|
|
|
|
left as an exercise for the reader. |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
The front-end JavaScript code is discussed in |
39
|
|
|
|
|
|
|
http://serversideguy.blogspot.com/2004/12/google-suggest-dissected.html . |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
This module is used by creating a subclass, which should override the |
42
|
|
|
|
|
|
|
C method, which takes care of searching for the autocompletion results. |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
=head1 METHODS |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
=over |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
=item $class->run(%args) |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
Run the whole autocompletion process in one fell swoop. Prints everything to |
51
|
|
|
|
|
|
|
standard output, including the HTTP headers. The arguments %args are passed to |
52
|
|
|
|
|
|
|
the constructor. |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
=cut |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
sub run { |
57
|
0
|
|
|
0
|
1
|
0
|
my $class = shift; |
58
|
0
|
|
|
|
|
0
|
my $self = $class->new(@_); |
59
|
0
|
|
|
|
|
0
|
print $self->header; |
60
|
0
|
0
|
|
|
|
0
|
print($self->no_js), return unless $self->param('js'); |
61
|
0
|
|
|
|
|
0
|
my ($query, $names, $values, $prefix) = $self->expand($self->query); |
62
|
0
|
|
|
|
|
0
|
print $self->output($query, $names, $values, $prefix); |
63
|
|
|
|
|
|
|
} |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
=item $class->new(%args) |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
Create a new JavaScript::Autocomplete::Backend object. Currently the only |
68
|
|
|
|
|
|
|
argument is C, which should provide a L or CGI-compatible object. If |
69
|
|
|
|
|
|
|
none is provided, a new L object is created by default. |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
=cut |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
sub new { |
74
|
2
|
|
|
2
|
1
|
506
|
my ($class, %args) = @_; |
75
|
2
|
|
33
|
|
|
20266
|
my $cgi = $args{cgi} || (require CGI, CGI->new); |
76
|
2
|
|
|
|
|
56582
|
bless { |
77
|
|
|
|
|
|
|
cgi => $cgi, |
78
|
|
|
|
|
|
|
}, $class; |
79
|
|
|
|
|
|
|
} |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
=item $obj->query |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
Returns the string to be expanded (which usually comes from the "qu" CGI |
84
|
|
|
|
|
|
|
parameter). |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
=cut |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
sub query { |
89
|
2
|
|
|
2
|
1
|
2062
|
shift->param('qu'); |
90
|
|
|
|
|
|
|
} |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
=item $obj->cgi |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
Returns the CGI object being used. |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
=cut |
97
|
|
|
|
|
|
|
|
98
|
6
|
|
|
6
|
1
|
430
|
sub cgi { shift->{cgi} } |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
=item $obj->param($name) |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
Get a CGI parameter. Just delegates the call to $self->cgi. |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
=cut |
105
|
|
|
|
|
|
|
|
106
|
3
|
|
|
3
|
1
|
289
|
sub param { shift->cgi->param(@_) } |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
=item $obj->header(%args) |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
Return the HTTP headers. It just delegates to $self->cgi, but it uses the |
111
|
|
|
|
|
|
|
UTF-8 encoding by default. |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
=cut |
114
|
|
|
|
|
|
|
|
115
|
2
|
|
|
2
|
1
|
398
|
sub header { shift->cgi->header( -charset => 'utf-8', @_ ) } |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
=item $obj->output($query, $names, $values, $prefix) |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
Converts the expanded values into JavaScript, as expected by the calling |
120
|
|
|
|
|
|
|
frontend script. $query is a string; all the other parameters are array refs. |
121
|
|
|
|
|
|
|
Returns a string. |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
=cut |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
sub output { |
126
|
2
|
|
|
2
|
1
|
388
|
my ($self, $query, $names, $values, $prefix) = @_; |
127
|
2
|
|
|
|
|
7
|
my $ret = qq{sendRPCDone(frameElement, "$query", }; |
128
|
2
|
|
|
|
|
16
|
$ret .= $self->as_array($names). ", "; |
129
|
2
|
|
|
|
|
9
|
$ret .= $self->as_array($values). ", "; |
130
|
2
|
|
|
|
|
8
|
$ret .= $self->as_array($prefix). ");\n"; |
131
|
2
|
|
|
|
|
9
|
$ret; |
132
|
|
|
|
|
|
|
} |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
=item $obj->expand($query) |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
Provide the autocompleted values for the query. Returns a 4-element list: |
137
|
|
|
|
|
|
|
($query, $names, $values, $prefix). $query is the query as returned to the |
138
|
|
|
|
|
|
|
frontend script (typically converted to lowercase). $names is an array ref |
139
|
|
|
|
|
|
|
of results. $values is an array ref of values that are usually shown on the |
140
|
|
|
|
|
|
|
right-hand side of the drop-down box in the front end; it is used by Google |
141
|
|
|
|
|
|
|
for the estimated result count. The purpose of $prefix is not certain at this |
142
|
|
|
|
|
|
|
time, but it appears that if the array is empty, the drop-down menu appears but |
143
|
|
|
|
|
|
|
the word in the input box itself is not completed, while if the array is not |
144
|
|
|
|
|
|
|
empty (for example, contains an empty string as its only element), the |
145
|
|
|
|
|
|
|
word in the input box is completed as well. |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
=cut |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
sub expand { |
150
|
0
|
|
|
0
|
1
|
0
|
my ($self, $query) = @_; |
151
|
0
|
|
|
|
|
0
|
(lc $query, [],[],[]); |
152
|
|
|
|
|
|
|
} |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
=item $obj->as_array(\@arr) |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
Convert an array ref into a JavaScript Array constructor. Returns a string. |
158
|
|
|
|
|
|
|
For example, |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
print $obj->as_array(["a", "b", "c"]); |
161
|
|
|
|
|
|
|
# prints 'new Array("a", "b", "c")' |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
=cut |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
sub as_array { |
166
|
7
|
|
|
7
|
1
|
1707
|
my ($self, $a) = @_; |
167
|
7
|
|
|
|
|
20
|
'new Array(' . join(", ", map { qq("$_") } @$a) . ')'; |
|
9
|
|
|
|
|
43
|
|
168
|
|
|
|
|
|
|
} |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
=item $obj->no_js |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
Returns that message that is returned by the Google backend when the C |
173
|
|
|
|
|
|
|
CGI parameter is not true. |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
=cut |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
sub no_js { |
178
|
1
|
|
|
1
|
1
|
359
|
<
|
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
HTML |
190
|
|
|
|
|
|
|
} |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
=back |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
=head1 SEE ALSO |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
http://www.google.com/webhp?complete=1&hl=en |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
http://serversideguy.blogspot.com/2004/12/google-suggest-dissected.html |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
=head1 VERSION |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
0.10 |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
=head1 AUTHOR |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
Ivan Tubert-Brohman Eitub@cpan.orgE |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
=head1 COPYRIGHT |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
Copyright (c) 2004 Ivan Tubert-Brohman. All rights reserved. This program is |
211
|
|
|
|
|
|
|
free software; you can redistribute it and/or modify it under the same terms as |
212
|
|
|
|
|
|
|
Perl itself. |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
The original JavaScript frontend code is Copyright (c) 2004 Google, Inc. Use it |
215
|
|
|
|
|
|
|
at your own risk or write or find a free version. |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
=cut |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
1; |
220
|
|
|
|
|
|
|
|