Skip to content

Commit

Permalink
adds in autocomplete functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
mejackreed committed Apr 14, 2015
1 parent 1c9af3d commit 927c197
Show file tree
Hide file tree
Showing 15 changed files with 294 additions and 6 deletions.
4 changes: 0 additions & 4 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -347,9 +347,5 @@ DEPENDENCIES
squash_rails
squash_ruby
therubyracer
<<<<<<< HEAD
=======
turbolinks
twitter-typeahead-rails
>>>>>>> add typeahead js
uglifier (>= 1.3.0)
22 changes: 22 additions & 0 deletions app/assets/javascripts/modules/autocomplete.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
$(document).on('ready page:load', function() {
var terms = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
remote: {
url: '/suggest?q=%QUERY'
}
});

terms.initialize();

$('input.search_q').typeahead({
hint: true,
highlight: true,
minLength: 2
},
{
name: 'terms',
displayKey: 'term',
source: terms.ttAdapter()
});
});
1 change: 1 addition & 0 deletions app/assets/stylesheets/earthworks.css.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
@import 'modules/show';
@import 'modules/sul_footer';
@import 'modules/top_navbar';
@import 'modules/typeahead';
@import 'modules/zero_results';


Expand Down
31 changes: 31 additions & 0 deletions app/assets/stylesheets/modules/typeahead.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
.twitter-typeahead {
float: left;
width: 100%;
z-index: 10000;

.tt-input.form-control {
width: 100%;
}

.tt-hint.form-control {
width: 100%;
}

.tt-dropdown-menu {
@extend .dropdown-menu;
font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif;

width: 100%;

.tt-suggestion p{
font-size: 14px;
padding-left: 10px;
}

.tt-cursor {
background-color: $dropdown-link-hover-bg;
color: $dropdown-link-hover-color;
text-decoration: none;
}
}
}
3 changes: 3 additions & 0 deletions app/controllers/suggest_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class SuggestController < ApplicationController
include Earthworks::Suggest
end
3 changes: 3 additions & 0 deletions config/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ class Application < Rails::Application
config.application_name = 'EarthWorks'

require 'rights_metadata'
require 'suggest/response'
require 'suggest/search_helper'
require 'suggest'
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automatically loaded.
Expand Down
2 changes: 2 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
match 'users/auth/webauth/logout' => 'devise/sessions#destroy', :as => :destroy_user_session, :via => Devise.mappings[:user].sign_out_via
end

resources :suggest, only: :index, defaults: { format: 'json' }

resource :feedback_form, path: 'feedback', only: [:new, :create]
get 'feedback' => 'feedback_forms#new'
# The priority is based upon order of creation: first created -> highest priority.
Expand Down
32 changes: 31 additions & 1 deletion config/solr_configs/schema.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@
termVectors="true" termPositions="true" termOffsets="true"/>
<dynamicField name="*_sort" type="text_sort" stored="false" indexed="true" multiValued="false"/>

<dynamicField name="*spell" type="text_en" indexed="true" stored="false" multiValued="true" />
<dynamicField name="*spell" type="textSpell" indexed="true" stored="false" multiValued="true" />

<dynamicField name="*suggest" type="textSuggest" indexed="true" stored="false" multiValued="true" />

<!-- Spatial field types:
Solr3:
Expand Down Expand Up @@ -113,6 +116,25 @@
</analyzer>
</fieldType>

<fieldType class="solr.TextField" name="textSuggest" positionIncrementGap="100">
<analyzer>
<tokenizer class="solr.KeywordTokenizerFactory"/>
<filter class="solr.StandardFilterFactory"/>
<filter class="solr.LowerCaseFilterFactory"/>
<filter class="solr.RemoveDuplicatesTokenFilterFactory"/>
</analyzer>
</fieldType>

<fieldType name="textSpell" class="solr.TextField" positionIncrementGap="100" >
<analyzer>
<tokenizer class="solr.StandardTokenizerFactory"/>
<filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt"/>
<filter class="solr.StandardFilterFactory"/>
<filter class="solr.LowerCaseFilterFactory"/>
<filter class="solr.RemoveDuplicatesTokenFilterFactory"/>
</analyzer>
</fieldType>

<!-- Spatial field types -->
<fieldType name="location" class="solr.LatLonType" subFieldSuffix="_d"/>

Expand Down Expand Up @@ -163,4 +185,12 @@
<copyField source="dct_provenance_s" dest="spell"/>
<copyField source="dc_subject_sm" dest="spell"/>
<copyField source="dct_spatial_sm" dest="spell"/>

<!-- for suggestions -->
<copyField source="dc_title_s" dest="suggest"/>
<copyField source="dc_creator_sm" dest="suggest"/>
<copyField source="dc_publisher_s" dest="suggest"/>
<copyField source="dct_provenance_s" dest="suggest"/>
<copyField source="dc_subject_sm" dest="suggest"/>
<copyField source="dct_spatial_sm" dest="suggest"/>
</schema>
23 changes: 22 additions & 1 deletion config/solr_configs/solrconfig.xml
Original file line number Diff line number Diff line change
Expand Up @@ -209,4 +209,25 @@
-->
</lst>
</searchComponent>
</config>

<searchComponent name="suggest" class="solr.SuggestComponent">
<lst name="suggester">
<str name="name">mySuggester</str>
<str name="lookupImpl">FuzzyLookupFactory</str>
<str name="suggestAnalyzerFieldType">textSuggest</str>
<str name="buildOnCommit">true</str>
<str name="field">suggest</str>
</lst>
</searchComponent>

<requestHandler name="/suggest" class="solr.SearchHandler" startup="lazy">
<lst name="defaults">
<str name="suggest">true</str>
<str name="suggest.count">5</str>
<str name="suggest.dictionary">mySuggester</str>
</lst>
<arr name="components">
<str>suggest</str>
</arr>
</requestHandler>
</config>
17 changes: 17 additions & 0 deletions lib/suggest.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module Earthworks
module Suggest
extend ActiveSupport::Concern
include Suggest::SearchHelper

##
# Get suggestion results from the Solr index
def index
@response = get_suggestions params
respond_to do |format|
format.json do
render json: @response.suggestions
end
end
end
end
end
24 changes: 24 additions & 0 deletions lib/suggest/response.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
module Earthworks
module Suggest
class Response
attr_reader :response, :request_params

##
# Creates a suggest response
# @param [RSolr::HashWithResponse] response
# @param [Hash] request_params
def initialize(response, request_params)
@response = response
@request_params = request_params
end

##
# Trys the suggestor response to return suggestions if they are
# present
# @return [Array]
def suggestions
response.try(:[], 'suggest').try(:[], 'mySuggester').try(:[], request_params[:q]).try(:[], 'suggestions') || []
end
end
end
end
26 changes: 26 additions & 0 deletions lib/suggest/search_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
module Earthworks
module Suggest
module SearchHelper
extend ActiveSupport::Concern
include Blacklight::SearchHelper

##
# For now, only use the q parameter to create a
# Earthworks::Suggest::Response
# @param [Hash] params
# @return [Earthworks::Suggest::Response]
def get_suggestions(params)
request_params = { q: params[:q] }
Earthworks::Suggest::Response.new suggest_results(request_params), request_params
end

##
# Query the suggest handler using RSolr::Client::send_and_receive
# @param [Hash] request_params
# @return [RSolr::HashWithResponse]
def suggest_results(request_params)
repository.connection.send_and_receive('suggest', params: request_params)
end
end
end
end
20 changes: 20 additions & 0 deletions spec/controllers/suggest_controller_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
require 'rails_helper'

describe SuggestController do
describe 'GET index' do
it 'assigns @response' do
get :index, format: 'json'
expect(assigns(:response)).to be_an Earthworks::Suggest::Response
end
it 'renders json' do
get :index, format: 'json'
expect(response.body).to eq [].to_json
end
it 'returns suggestions' do
get :index, format: 'json', q: 'st'
json = JSON.parse(response.body)
expect(json.count).to eq 2
expect(json.first['term']).to eq 'stanford'
end
end
end
48 changes: 48 additions & 0 deletions spec/lib/suggest/response_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
require 'rails_helper'

describe Earthworks::Suggest::Response do
let(:empty_response) { Earthworks::Suggest::Response.new({}, q: 'hello') }
let(:response) do
Earthworks::Suggest::Response.new(
{
'responseHeader' => {
'status' => 0,
'QTime' => 42
},
'suggest' => {
'mySuggester' => {
'st' => {
'numFound' => 2,
'suggestions' => [
{
'term' => 'stanford',
'weight' => 3,
'payload' => ''
},
{
'term' => 'statistics',
'weight' => 1,
'payload' => ''
}
]
}
}
}
},
q: 'st'
)
end

describe '#initialize' do
it 'creates a Earthworks::Suggest::Response' do
expect(empty_response).to be_an Earthworks::Suggest::Response
end
end
describe '#suggestions' do
it 'returns an array of suggestions' do
expect(response.suggestions).to be_an Array
expect(response.suggestions.count).to eq 2
expect(response.suggestions.first['term']).to eq 'stanford'
end
end
end
44 changes: 44 additions & 0 deletions spec/lib/suggest/search_helper_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
require 'rails_helper'

describe Earthworks::Suggest::SearchHelper do

class SearchHelperTestClass
include Earthworks::Suggest::SearchHelper

attr_accessor :blacklight_config
attr_accessor :repository

def initialize blacklight_config, conn
self.blacklight_config = blacklight_config
self.repository = Blacklight::SolrRepository.new(blacklight_config)
self.repository.connection = conn
end

def params
{}
end
end

subject { SearchHelperTestClass.new blacklight_config, blacklight_solr }

let(:blacklight_config) { Blacklight::Configuration.new }
let(:copy_of_catalog_config) { ::CatalogController.blacklight_config.deep_copy }
let(:blacklight_solr) { RSolr.connect(Blacklight.connection_config) }



describe '#get_suggestions' do
it 'returns a Earthworks::Suggest::Response' do
expect(subject.get_suggestions q: 'test').to be_an Earthworks::Suggest::Response
end
end
describe '#suggest_results' do
it 'queries the suggest handler with params' do
allow(blacklight_solr).to receive(:get) do |path, params|
expect(path).to eq 'suggest'
expect(params).to eq params: { q: 'st' }
end
subject.query_solr q: 'st'
end
end
end

0 comments on commit 927c197

Please sign in to comment.