Skip to content

Commit

Permalink
Merge pull request #1836 from metacpan/haarg/local-author-autocomplete
Browse files Browse the repository at this point in the history
local author autocomplete
  • Loading branch information
oalders committed Dec 22, 2016
2 parents 050fb39 + 7c0c876 commit d5b53b6
Show file tree
Hide file tree
Showing 8 changed files with 78 additions and 138 deletions.
30 changes: 20 additions & 10 deletions lib/MetaCPAN/Web/Controller/Search/AutoComplete.pm
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,35 @@ package MetaCPAN::Web::Controller::Search::AutoComplete;

use Moose;
use Cpanel::JSON::XS ();

use Importer 'MetaCPAN::Web::Elasticsearch::Adapter' =>
qw/ single_valued_arrayref_to_scalar /;
use List::Util qw(uniq);

use namespace::autoclean;

BEGIN { extends 'MetaCPAN::Web::Controller' }

sub index : Path : Args(0) {
my ( $self, $c ) = @_;
my $model = $c->model('API::Module');
my $query = join( q{ }, $c->req->param('q') );
my $data = $model->autocomplete($query)->recv;
my $query = join( q{ }, $c->req->param('q') );
my $module_data = $c->model('API::Module')->autocomplete($query);
my $author_data = $c->model('API::Author')->search($query);
my @results = (
(
map +{
value => "$_->{pauseid} - $_->{name}",
data => { id => $_->{pauseid}, type => 'author' }
},
@{ $author_data->recv->{results} }
),
(
map +{ value => $_, data => { module => $_, type => 'module' } },
uniq map $_->{documentation},
@{ $module_data->recv->{results} }
),
);

$c->res->content_type('application/json');
$c->res->body(
Cpanel::JSON::XS::encode_json(
single_valued_arrayref_to_scalar( $data->{results} )
)
);
Cpanel::JSON::XS::encode_json( { suggestions => \@results } ) );
}

__PACKAGE__->meta->make_immutable;
Expand Down
2 changes: 1 addition & 1 deletion lib/MetaCPAN/Web/Model/API/Module.pm
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ sub autocomplete {
my ( $self, $query ) = @_;
my $cv = $self->cv;
$self->request( "/search/autocomplete", undef,
{ q => $query, size => 20 } )->cb(
{ q => $query, size => 50 } )->cb(
sub {
my $data = shift->recv;
$cv->send(
Expand Down
5 changes: 5 additions & 0 deletions root/inc/pager.html
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,8 @@
</ul>
</div>
<% END %>

<div class="text-center smaller">
<% total | format_number %>
<% "result".pluralize(total) %> (<% took / 1000 %> seconds)
</div>
126 changes: 40 additions & 86 deletions root/static/js/cpan.js
Original file line number Diff line number Diff line change
Expand Up @@ -194,96 +194,50 @@ $(document).ready(function() {
var search_input = $("#search-input");
var input_group = search_input.parent('.input-group');
var ac_width = (input_group.length ? input_group : search_input).outerWidth();
search_input.bind('modules_autocomplete', function() {
$(this).autocomplete({
serviceUrl: '/search/autocomplete',
// Wait for more typing rather than firing at every keystroke.
deferRequestBy: 150,
// If the autocomplete fires with a single colon ("type:") it will get no results
// and anything else typed after that will never trigger another query.
// Set 'preventBadQueries:false' to keep trying.
preventBadQueries: false,
dataType: 'json',
lookupLitmit: 20,
paramName: 'q',
autoSelectFirst: false,
// This simply caches the results of a previous search by url (so no reason not to).
noCache: false,
triggerSelectOnValidInput: false,
maxHeight: 180,
width: ac_width,
transformResult: function(data) {
var result = $.map(data, function(row) {
return {
data: row.documentation,
value: row.documentation
};
});
var uniq = {};
result = $.grep(result, function(row) {
uniq[row.value] = typeof(uniq[row.value]) == 'undefined' ? 0 : uniq[row.value];
return uniq[row.value]++ < 1;
});
return {
suggestions: result
};
},
onSelect: function(suggestion) {
document.location.href = '/pod/' + suggestion.value;
search_input.autocomplete({
serviceUrl: '/search/autocomplete',
// Wait for more typing rather than firing at every keystroke.
deferRequestBy: 150,
// If the autocomplete fires with a single colon ("type:") it will get no results
// and anything else typed after that will never trigger another query.
// Set 'preventBadQueries:false' to keep trying.
preventBadQueries: false,
dataType: 'json',
lookupLitmit: 20,
paramName: 'q',
autoSelectFirst: false,
// This simply caches the results of a previous search by url (so no reason not to).
noCache: false,
triggerSelectOnValidInput: false,
maxHeight: 180,
width: ac_width,
onSelect: function(suggestion) {
if (suggestion.data.type == 'module') {
document.location.href = '/pod/' + suggestion.data.module;
} else if (suggestion.data.type == 'author') {
document.location.href = '/author/' + suggestion.data.id;
}
});

// Disable the built-in hover events to work around the issue that
// if the mouse pointer is over the box before it appears the event may fire erroneously.
// Besides, does anybody really expect an item to be selected just by
// hovering over it? Seems unintuitive to me. I expect anyone would either
// click or hit a key to actually pick an item, and who's going to hover to
// the item they want and then instead of just clicking hit tab/enter?
$('.autocomplete-suggestions').off('mouseover.autocomplete');
$('.autocomplete-suggestions').off('mouseout.autocomplete');
});

search_input.bind('authors_autocomplete', function() {
$(this).constructorAutocomplete({
key: 'bQssESEa8XUBKzSUjarO',
directResults: true,
maxHeight: 400,
transformResult: function(response) {
if (response['sections'] && response['sections']['url']) {
response['sections']['url'].forEach(function(dataset) {
if (dataset.value) {
dataset.value = dataset.value.replace(/^[^:]+: /, "");
}
});
}
return response;
}
});

// Disable the built-in hover events (see comment above)
$('.autocomplete-suggestions').off('mouseover.autocomplete');
$('.autocomplete-suggestions').off('mouseout.autocomplete');
});
search_input.trigger('modules_autocomplete');
$.getScript("//cnstrc.com/js/ac.js", function() {
if ($('input[name=search_type]:checked').val() == "authors") {
search_input.trigger('authors_autocomplete');
}
});

$("input[name=search_type]").click(function() {
if ($(this).val() == "authors") {
if (typeof $("#search-input").autocomplete === "function") {
$("#search-input").autocomplete("dispose");
}
search_input.trigger('authors_autocomplete');
} else {
if (typeof $("#search-input").constructorAutocomplete === "function") {
$("#search-input").constructorAutocomplete("dispose");
}
search_input.trigger('modules_autocomplete');
var ac = search_input.autocomplete();
var formatResult = ac.options.formatResult;
ac.options.formatResult = function(suggestion, currentValue) {
var out = formatResult(suggestion, currentValue);
if (suggestion.data.type == 'author') {
return "<span class=\"suggest-author-label\">Author:</span> " + out;
}
});
return out;
};


// Disable the built-in hover events to work around the issue that
// if the mouse pointer is over the box before it appears the event may fire erroneously.
// Besides, does anybody really expect an item to be selected just by
// hovering over it? Seems unintuitive to me. I expect anyone would either
// click or hit a key to actually pick an item, and who's going to hover to
// the item they want and then instead of just clicking hit tab/enter?
$('.autocomplete-suggestions').off('mouseover.autocomplete');
$('.autocomplete-suggestions').off('mouseout.autocomplete');

$('#search-input.autofocus').focus();

Expand Down
Loading

0 comments on commit d5b53b6

Please sign in to comment.