blacklight_advanced_search 1.0.0pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/.gitignore +5 -0
  2. data/LICENSE +14 -0
  3. data/README.rdoc +172 -0
  4. data/Rakefile +6 -0
  5. data/VERSION +1 -0
  6. data/app/controllers/advanced_controller.rb +61 -0
  7. data/app/controllers/application_controller.rb +5 -0
  8. data/app/helpers/advanced_helper.rb +40 -0
  9. data/app/views/advanced/_advanced_search_facets.html.erb +16 -0
  10. data/app/views/advanced/_advanced_search_fields.html.erb +6 -0
  11. data/app/views/advanced/_advanced_search_form.html.erb +48 -0
  12. data/app/views/advanced/_advanced_search_help.html.erb +22 -0
  13. data/app/views/advanced/index.html.erb +10 -0
  14. data/app/views/blacklight_advanced_search/_facet_limit.html.erb +25 -0
  15. data/blacklight_advanced_search.gemspec +24 -0
  16. data/config/routes.rb +3 -0
  17. data/install.rb +0 -0
  18. data/lib/blacklight_advanced_search/advanced_query_parser.rb +61 -0
  19. data/lib/blacklight_advanced_search/catalog_helper_override.rb +53 -0
  20. data/lib/blacklight_advanced_search/controller.rb +101 -0
  21. data/lib/blacklight_advanced_search/engine.rb +47 -0
  22. data/lib/blacklight_advanced_search/filter_parser.rb +13 -0
  23. data/lib/blacklight_advanced_search/parsing_nesting_parser.rb +18 -0
  24. data/lib/blacklight_advanced_search/render_constraints_override.rb +96 -0
  25. data/lib/blacklight_advanced_search/version.rb +10 -0
  26. data/lib/blacklight_advanced_search.rb +74 -0
  27. data/lib/generators/blacklight_advanced_search/assets_generator.rb +25 -0
  28. data/lib/generators/blacklight_advanced_search/blacklight_advanced_search_generator.rb +11 -0
  29. data/lib/generators/blacklight_advanced_search/templates/_search_form.html.erb +13 -0
  30. data/lib/generators/blacklight_advanced_search/templates/blacklight_advanced_search_config.rb +86 -0
  31. data/lib/generators/blacklight_advanced_search/templates/public/javascripts/blacklight_advanced_search_javascript.js +62 -0
  32. data/lib/generators/blacklight_advanced_search/templates/public/stylesheets/advanced_results.css +41 -0
  33. data/lib/generators/blacklight_advanced_search/templates/public/stylesheets/blacklight_advanced_search_styles.css +129 -0
  34. data/lib/parsing_nesting/Readme.rdoc +160 -0
  35. data/lib/parsing_nesting/grammar.rb +78 -0
  36. data/lib/parsing_nesting/tree.rb +457 -0
  37. data/spec/lib/filter_parser_spec.rb +28 -0
  38. data/spec/parsing_nesting/build_tree_spec.rb +238 -0
  39. data/spec/parsing_nesting/consuming_spec.rb +49 -0
  40. data/spec/parsing_nesting/to_solr_spec.rb +360 -0
  41. data/spec/rcov.opts +3 -0
  42. data/spec/spec.opts +4 -0
  43. data/spec/spec_helper.rb +9 -0
  44. data/spec/support/blacklight_mock.rb +5 -0
  45. data/uninstall.rb +1 -0
  46. metadata +164 -0
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ .DS_Store
2
+ coverage.data
3
+ coverage/
4
+ log/*
5
+ *.log
data/LICENSE ADDED
@@ -0,0 +1,14 @@
1
+ ##########################################################################
2
+ # Copyright 2010 Stanford University
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
data/README.rdoc ADDED
@@ -0,0 +1,172 @@
1
+ This is an advanced search plugin for Blacklight ( http://www.projectblacklight.org ). It is meant to be installed alongside the Blacklight plugin in your application's vendor/plugins directory.
2
+
3
+
4
+ == Pre-requisites:
5
+ * The Blacklight plugin ( http://github.com/projectblacklight/blacklight )
6
+ * NOTE: 2.9 or later is required for current version of Advanced Search plugin. Older tagged versions of Advanced Search may work with older BL.
7
+ * Parslet gem ( https://github.com/kschiess/parslet )
8
+
9
+ == Installation:
10
+ Clone the advanced search plugin from github into your application's vendor/plugins directory
11
+ * cd into your application's vendor/plugins directory and run the following command:
12
+ git clone http://github.com/projectblacklight/blacklight_advanced_search.git
13
+
14
+ You can later use standard git commands to update the plugin to a new version.
15
+
16
+ OR
17
+
18
+ from your application's main directory, run:
19
+
20
+ ./script/plugin install http://github.com/projectblacklight/blacklight_advanced_search.git
21
+
22
+
23
+ You can later use "./script/plugin update blacklight_advanced_search" to update to latest code.
24
+
25
+ You will now need to add a parslet gem dependency to your app, since blacklight_advanced_search is not currently a gem itself, you have to do this manually. Add "config.gem 'parslet'" to your config/environment.rb, and then run:
26
+
27
+ sudo rake gems:install
28
+
29
+ You can also now *optionally* run the installer script to install some optional example configuration files. In many cases, no configuration is needed for advanced search plugin to work.
30
+ * cd back to your application's root directory
31
+ cd ../../
32
+ * And then run the the following command:
33
+ rake rails:template LOCATION=vendor/plugins/blacklight_advanced_search/template.rb
34
+
35
+ You may want to set BlacklightAdvancedSearch.config[:advanced_parse_q] = true to enable AND/OR/NOT parsing even in ordinary search, this is not on by default.
36
+
37
+ == Accessing
38
+
39
+
40
+ The advanced search form will be available in your app at /advanced
41
+
42
+ url_for(:controller => "advanced", :action => "index")
43
+
44
+ You can also send the advanced search form url parameters representing a search, to have the form add on additional 'advanced' criteria to the search. For example:
45
+
46
+ url_for( params.merge(:controller => "advanced", :action => "index")
47
+
48
+ If you do not have the default :controller/:action route enabled for your application, you may need to add a custom route to config/routes.rb. For example:
49
+
50
+ map.advanced 'advanced', :controller => 'advanced', :action => 'index'
51
+
52
+ By default there won't be any links in your application to the search form. If you've heavily customized your app, you can put them wherever you want as above.
53
+
54
+ However, especially if your app isn't much customized, the optional installer can write a localized Blacklight search form into your application with a 'more options' link to advanced. You may need to adjust your styles to make room for the new link, depending on what you've done with your app.
55
+
56
+
57
+
58
+ == Configuration:
59
+
60
+ If your application uses a single Solr qt request handler for all its search fields, then this plugin may work well with no configuration. Nonetheless, configuration is available to change or improve behavior, or to use a separate Solr request handler for the advanced search plugin.
61
+
62
+ All plugin configuration mentioned below can be in any initializer in your app (any ruby file in config/initializers), although using the convention config/initializers/blacklight_advanced_search.rb may keep things clear.
63
+
64
+ The optional installer script can install a sample blacklight_advanced_search.rb for you which demonstrates various options.
65
+
66
+ === Expression parsing in ordinary search
67
+
68
+ If you turn on this feature with `BlacklightAdvancedSearch.config[:advanced_parse_q] = true`, then the plugin will intercept queries entered in ordinary Blacklight search interface, and parse them for AND/OR/NOT (and parens), producing appropriate Solr query. This allows single-field boolean expressions to be entered in ordinary search, providing a consistent experience with advanced search.
69
+
70
+ When this feature is turned on, queries that don't have any special operators (eg: AND, OR, NOT, parens) will still be passed to Solr much the same as they were before. But queries with special operators will have appropriate Solr queries generated for them, usually including nested "_query_" elements, to have the same meaning they would in advanced search.
71
+
72
+ Due to limitations of the logic, sometimes these generated Solr queries may not really be as simple as they could be, they may include a *single* nested _query_, which really doens't need to be a nested query at all, although it will still work fine.
73
+
74
+ === Search fields
75
+
76
+ Your main blacklight search fields are generally defined in config/blacklight_config.rb, under "config[:search_fields]" ( https://github.com/projectblacklight/blacklight/blob/master/config/initializers/blacklight_config.rb#L194 ). If there are particular search fields in your main blacklight config you want excluded from the advanced search form, you can set ":include_in_advanced_search => false"
77
+
78
+ All advanced search fields must share the same Solr request handler (":qt"). As such, search fields that use a custom ":qt" parameter may not be re-used by the advanced search plugin. However, you may use a separate Solr request handler than the Blacklight default. If you would like the advanced search to use a different Solr request handler than your app's default, set:
79
+ BlacklightAdvancedSearch.config[:qt]
80
+ to the name of the Solr request handler.
81
+
82
+ If you use a separate Solr request handler for advanced search, you must supply a completely separate list of search fields for the advanced search form. Each field is defined by a hash whose format is specified in Blacklight::SearchFields ( https://github.com/projectblacklight/blacklight/blob/master/lib/blacklight/search_fields.rb#L7 ).
83
+
84
+ BlacklightAdvancedSearch.config[:search_fields] = []
85
+ BlacklightAdvancedSearch.config[:search_fields] << {
86
+ :key => 'title',
87
+ :solr_local_parameters => {
88
+ :qf => "title_t subtitle_t addl_titles_t title_unstem_search^1000" # see ( http://wiki.apache.org/solr/DisMaxQParserPlugin#qf_.28Query_Fields.29 )
89
+ :pf => "title_t subtitle_t addl_titles_t title_unstem_search^1000" # see ( http://wiki.apache.org/solr/DisMaxQParserPlugin#pf_.28Phrase_Fields.29 )
90
+ }
91
+ }
92
+
93
+ Additionally, to make your advanced search solr requests more concise, you are strongly encouraged to take advantage of the :local_solr_parameters option in your search field definition to use a solr parameter substitution with $variables.
94
+
95
+ BlacklightAdvancedSearch.config[:search_fields] << {
96
+ :key => 'author'
97
+ :solr_local_parameters => {
98
+ :qf=>"$qf_author",
99
+ :pf=>"$pf_author"
100
+ }
101
+ }
102
+
103
+ Within your solrconfig.xml you may then provide the appropriate custom configuration.
104
+
105
+ <requestHandler name="advanced" class="solr.SearchHandler" >
106
+ <lst name="defaults">
107
+ <!-- ... -->
108
+ <str name="qf_author">
109
+ author_1xx_unstem_search^200
110
+ author_7xx_unstem_search^50
111
+ author_8xx_unstem_search^10
112
+ author_1xx_search^20 vern_author_1xx_search^20
113
+ author_7xx_search^5 vern_author_7xx_search^5
114
+ author_8xx_search vern_author_8xx_search
115
+ </str>
116
+ <str name="pf_author">
117
+ author_1xx_unstem_search^5000
118
+ author_7xx_unstem_search^3000
119
+ author_1xx_search^500 vern_author_1xx_search^500
120
+ author_7xx_search^300 vern_author_7xx_search^300
121
+ author_8xx_unstem_search^250
122
+ author_8xx_search^200 vern_author_8xx_search^200
123
+ </str>
124
+ </lst>
125
+ </requestHandler>
126
+
127
+
128
+ === Facets
129
+
130
+ By default, the advanced search form will show as limits whatever facets are configured as default in your Solr request handler. To have the advanced search form request specific facets and/or specific facet parameters, you can set config[:form_solr_parameters].
131
+
132
+ BlacklightAdvancedSearch.config[:form_solr_parameters] = {
133
+ "facet.field" => ["format", "language_facet"],
134
+ "facet.limit" => -1, # return all facet values
135
+ "facet.sort" => "index" # sort by byte order of values
136
+ }
137
+
138
+
139
+ === All Config Options
140
+
141
+ [config[:qt]]
142
+ Solr request handler to use for any search that includes advanced search criteria. Defaults to what the application has set as Blacklight.config[:default_qt]
143
+ [config[:url_key]]
144
+ Key to use in application URLs to indicate advanced search is included in a query, defaults to "advanced". URLs will have "&search_field=[url key]".
145
+ [config[:search_fields]]
146
+ Array of search field definitions to be used for advanced search. Each element in the array is a hash of the form required by Blacklight::SearchFields. If left blank, the plugin will use definitions from your main app Blacklight.config[:search_fields] -- only those which have no :qt set, and do not have :include_in_advanced_search => false.
147
+ [config[:form_solr_paramters]]
148
+ A hash of solr parameters which will be included in Solr request sent before display of advanced search form. Can be used to set facet parameters for advanced search form display.
149
+ [config[:advanced_parse_q]]
150
+ Set to 'true' to have AND/OR/NOT parsed even in ordinary 'simple' blacklight search, and converted to appropriate Solr query for that single field.
151
+
152
+ == Translation to Solr Query, technical details
153
+
154
+ The code for mapping a user-entered query to a Solr query is called "nesting_parsing", and maps to a 'lucene' query parser query, with nested 'dismax' query parser queries.
155
+
156
+ Some technical details can be found in the nesting_parsing README: [https://github.com/projectblacklight/blacklight_advanced_search/tree/master/lib/parsing_nesting]
157
+
158
+ You may also find the rspecs for parsing a user-entered query and converting it to Solr illumnating:
159
+ 1. Converting user-entered query to Solr: [https://github.com/projectblacklight/blacklight_advanced_search/blob/master/spec/parsing_nesting/to_solr_spec.rb]
160
+ 2. Parsing user-entered query to internal syntax tree: [https://github.com/projectblacklight/blacklight_advanced_search/blob/master/spec/parsing_nesting/build_tree_spec.rb]
161
+
162
+ == Running tests
163
+
164
+ Test coverage is provided with rspec, run all tests by running:
165
+ spec ./spec
166
+
167
+
168
+ == To Do
169
+
170
+ * Alphabetical sorting of facet values returned by solr in count order (perhaps with limit).
171
+
172
+
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ require 'bundler'
6
+ Bundler::GemHelper.install_tasks
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0pre1
@@ -0,0 +1,61 @@
1
+ # Need to sub-class CatalogController so we get all other plugins behavior
2
+ # for our own "inside a search context" lookup of facets.
3
+ class AdvancedController < CatalogController
4
+ include AdvancedHelper # so we get the #advanced_search_context method
5
+
6
+ before_filter :setup_advanced_search_css, :setup_advanced_search_js, :only => :index
7
+
8
+ def index
9
+ unless request.method==:post
10
+ @response = get_advanced_search_facets
11
+ end
12
+ end
13
+
14
+ protected
15
+ def get_advanced_search_facets
16
+
17
+ search_context_params = {}
18
+ if (advanced_search_context.length > 0 )
19
+ # We have a search context, need to fetch facets from within
20
+ # that context -- but we dont' want to search within any
21
+ # existing :q or ADVANCED facets, so we remove those params.
22
+ adv_keys = BlacklightAdvancedSearch.config[:search_fields].collect {|d| d[:key].to_sym}
23
+ trimmed_params = params.reject do |k,v|
24
+ adv_keys.include?(k.to_sym) # the individual q params
25
+ end
26
+ trimmed_params.delete(:f_inclusive) # adv facets
27
+
28
+ search_context_params = solr_search_params(trimmed_params)
29
+ # Don't want to include the 'q' from basic search in our search
30
+ # context. Kind of hacky becuase solr_search_params insists on
31
+ # using controller.params, not letting us over-ride.
32
+ search_context_params.delete(:q)
33
+ search_context_params.delete("q")
34
+
35
+ # Also delete any facet-related params, or anything else
36
+ # we want to set ourselves or inherit from Solr request handler
37
+ # defaults.
38
+ search_context_params.delete_if do |k, v|
39
+ k = k.to_s
40
+ (["facet.limit", "facet.sort", "f", "facets", "facet.fields", "qt", "per_page"].include?(k) ||
41
+ k =~ /f\..+\.facet\.limit/ ||
42
+ k =~ /f\..+\.facet\.sort/
43
+ )
44
+ end
45
+ end
46
+
47
+ input = HashWithIndifferentAccess.new
48
+ input.merge!( search_context_params )
49
+ input.merge!( :qt => BlacklightAdvancedSearch.config[:qt] , :per_page => 0)
50
+ input.merge!( BlacklightAdvancedSearch.config[:form_solr_parameters] )
51
+
52
+
53
+ Blacklight.solr.find(input.to_hash)
54
+ end
55
+ def setup_advanced_search_css
56
+ stylesheet_links << ["blacklight_advanced_search_styles", {:plugin=>:blacklight_advanced_search}]
57
+ end
58
+ def setup_advanced_search_js
59
+ javascript_includes << ["blacklight_advanced_search_javascript", {:plugin=>:blacklight_advanced_search}]
60
+ end
61
+ end
@@ -0,0 +1,5 @@
1
+ class ApplicationController < ActionController::Base
2
+ helper :all # include all helpers, all the time
3
+ protect_from_forgery # See ActionController::RequestForgeryProtection for details
4
+
5
+ end
@@ -0,0 +1,40 @@
1
+ # Helper methods for the advanced search form
2
+ module AdvancedHelper
3
+
4
+ # Fill in default from existing search, if present
5
+ # -- if you are using same search fields for basic
6
+ # search and advanced, will even fill in properly if existing
7
+ # search used basic search on same field present in advanced.
8
+ def label_tag_default_for(key)
9
+ if (! params[key].blank?)
10
+ return params[key]
11
+ elsif params["search_field"] == key
12
+ return params["q"]
13
+ else
14
+ return nil
15
+ end
16
+ end
17
+
18
+ # Is facet value in adv facet search results?
19
+ def facet_value_checked?(field, value)
20
+ params[:f_inclusive] && params[:f_inclusive][field] && params[:f_inclusive][field][value]
21
+ end
22
+
23
+ # Current params without fields that will be over-written by adv. search,
24
+ # or other fields we don't want.
25
+ def advanced_search_context
26
+ my_params = params.dup
27
+ [:page, :commit, :f_inclusive, :q, :search_field, :op, :action, :index, :sort, :controller].each do |bad_key|
28
+ my_params.delete(bad_key)
29
+ end
30
+ search_fields_for_advanced_search.each do |field_def|
31
+ my_params.delete( field_def[:key] )
32
+ end
33
+ my_params
34
+ end
35
+
36
+ def search_fields_for_advanced_search
37
+ BlacklightAdvancedSearch.config[:search_fields] || []
38
+ end
39
+
40
+ end
@@ -0,0 +1,16 @@
1
+ <% facet_field_names.each do |solr_fname| %>
2
+ <div class="facet_item">
3
+ <% display_facet = @response.facets.detect {|f| f.name == solr_fname} -%>
4
+ <% # if it's NOT a refinement facet -- they are handled in get_refine_facet -%>
5
+ <% if display_facet && display_facet.items.length > 0 %>
6
+ <h3><%= facet_field_labels[solr_fname] -%> <span class="adv_facet_selections" style="display:none;"></span></h3>
7
+ <ul>
8
+ <% display_facet.items.each do |item| -%>
9
+ <li>
10
+ <%= check_box_tag "f_inclusive[#{solr_fname}][#{item.value.to_sym}]", 1, facet_value_checked?(solr_fname, item.value)%> <%= label_tag "f_inclusive_#{solr_fname}[#{item.value.to_sym}]", h(item.value) %> (<%= format_num item.hits %>)
11
+ </li>
12
+ <% end -%>
13
+ </ul>
14
+ <% end %>
15
+ </div>
16
+ <% end %>
@@ -0,0 +1,6 @@
1
+ <%- BlacklightAdvancedSearch.search_field_list.each do |field_def| -%>
2
+ <div class="advanced_search_field">
3
+ <%= label_tag field_def[:key], "#{field_def[:display_label] }:" %>
4
+ <%= text_field_tag field_def[:key], label_tag_default_for(field_def[:key]) %>
5
+ </div>
6
+ <%- end -%>
@@ -0,0 +1,48 @@
1
+ <% form_tag catalog_index_path, :class => 'advanced', :method => :get do %>
2
+
3
+ <%= search_as_hidden_fields(:params => advanced_search_context ) %>
4
+
5
+ <div class="input_columns yui-g">
6
+
7
+ <div class="yui-u first">
8
+
9
+ <div class="query_column column">
10
+ <h2>Find items that match <%= select_tag(:op, options_for_select({'all'=>'AND','any'=>'OR'}.sort,'all')) %> of the fields below:</h2>
11
+
12
+ <div id="advanced_search">
13
+ <%= render 'advanced/advanced_search_fields' %>
14
+ </div>
15
+ </div>
16
+
17
+ </div>
18
+
19
+ <div class="yui-u">
20
+
21
+ <div class="limit_column column">
22
+ <h2><strong>AND</strong> have these attributes:</h2>
23
+
24
+ <div id="advanced_search_facets" class="limit_input">
25
+ <%= render 'advanced_search_facets' %>
26
+ </div>
27
+ </div>
28
+
29
+ </div>
30
+
31
+ </div>
32
+
33
+ <% unless (search_context_str = render_search_to_s( advanced_search_context)).blank? %>
34
+ <div class="constraints">
35
+ <h4>Within search:</h4>
36
+ <%= search_context_str %>
37
+ </div>
38
+ <% end %>
39
+
40
+
41
+ <div class="sort_submit_buttons">
42
+ <%= label_tag(:sort, "Sort results by") %>
43
+ <%= select_tag(:sort, options_for_select(Blacklight.config[:sort_fields],'')) %>
44
+ <%= hidden_field_tag(:search_field, BlacklightAdvancedSearch.config[:url_key]) %>
45
+ <%= submit_tag 'Search', :class=>'advanced_button', :id=>'advanced_search' %>
46
+ <%= link_to "Start over", {:controller => "advanced", :action => "index"}, :class =>"reset advanced_button" %>
47
+ </div>
48
+ <% end %>
@@ -0,0 +1,22 @@
1
+ <div>
2
+ <h2>Search tips</h2>
3
+ <ul class="advanced_help">
4
+ <li>Select "match all" to require all fields.
5
+ </li>
6
+
7
+ <li>Select "match any" to find at least one field.
8
+ </li>
9
+
10
+ <li>Combine keywords and attributes to find specific items.
11
+ </li>
12
+
13
+ <li>Use quotation marks to search as a phrase.
14
+
15
+ <li>Use "+" before a term to make it required. (Otherwise results matching only some of your terms may be included).</li>
16
+
17
+ <li>Use "-" before a word or phrase to exclude.
18
+
19
+ <li>Use "OR", "AND", and "NOT" to create complex boolean logic. You can use parentheses in your complex expressions. </li>
20
+ <li>Truncation and wildcards are not supported - word-stemming is done automatically.</li>
21
+ </ul>
22
+ </div>
@@ -0,0 +1,10 @@
1
+ <% @page_title = "More Search Options - #{application_name}" %>
2
+ <script type="text/javascript">
3
+ $(document).ready(function(){$("form.advanced input:first").focus();});
4
+ </script>
5
+
6
+ <h1 class="advanced">More Search Options</h1>
7
+ <%= render 'advanced_search_form' %>
8
+ <%- sidebar_items << capture do -%>
9
+ <%= render "advanced_search_help" %>
10
+ <%- end -%>
@@ -0,0 +1,25 @@
1
+ <%-
2
+ # Custom facet_limit partial that displays inclusive 'or' advanced facet
3
+ # limits at the top, then lets you drill down into ordinary facets.
4
+ #
5
+ # pass in :solr_field local.
6
+ #
7
+ # Assumes an @advanced_query exists, and probably has #filters for this
8
+ # solr_field.
9
+ -%>
10
+
11
+ <h3><%= facet_field_labels[solr_field] -%></h3>
12
+
13
+ <div class="advanced_facet_limit">
14
+ <div class="inclusive_or">
15
+ <h4>Any of:</h4>
16
+ <ul>
17
+ <% @advanced_query.filters[solr_field].each do |value| %>
18
+ <li><span class="selected"><%= h(value) %></span> <%= link_to "[remove]", remove_advanced_facet_param(solr_field, value), :class=>"remove" %></li>
19
+ <% end %>
20
+ </ul>
21
+ </div>
22
+
23
+ <%= render(:partial => "catalog/facet_limit", :locals => {:solr_field => solr_field, :display_heading => false}) %>
24
+
25
+ </div>
@@ -0,0 +1,24 @@
1
+ # -*- coding: utf-8 -*-
2
+ require "lib/blacklight_advanced_search/version"
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "blacklight_advanced_search"
6
+ s.version = BlacklightAdvancedSearch::VERSION
7
+ s.platform = Gem::Platform::RUBY
8
+ s.authors = ["Jonathan Rochkind", "Chris Beer"]
9
+ s.email = ["blacklight-development@googlegroups.com"]
10
+ s.homepage = "http://projectblacklight.org/"
11
+ s.summary = "Blacklight Advanced Search plugin"
12
+
13
+ s.rubyforge_project = "blacklight"
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ["lib"]
19
+
20
+
21
+ s.add_dependency "rails", "~> 3.0"
22
+ s.add_dependency "blacklight"
23
+ s.add_dependency "parslet"
24
+ end
data/config/routes.rb ADDED
@@ -0,0 +1,3 @@
1
+ Rails.application.routes.draw do
2
+ match 'advanced' => 'advanced#index'
3
+ end
data/install.rb ADDED
File without changes
@@ -0,0 +1,61 @@
1
+ module BlacklightAdvancedSearch
2
+ class QueryParser
3
+ include ParsingNestingParser # only one strategy currently supported. if BlacklightAdvancedSearch.config[:solr_type] == "parsing_nesting"
4
+ include FilterParser
5
+ attr_reader :config, :params
6
+
7
+ def initialize(params,config)
8
+ @params = HashWithIndifferentAccess.new(params)
9
+ @config = config
10
+ end
11
+
12
+ def to_solr
13
+ @to_solr ||= begin
14
+ {
15
+ :q => process_query(params,config),
16
+ :fq => generate_solr_fq()
17
+ }
18
+ end
19
+ end
20
+
21
+ # Returns "AND" or "OR", how #keyword_queries will be combined
22
+ def keyword_op
23
+ @params["op"] || "AND"
24
+ end
25
+ # returns advanced-type keyword queries, see also keyword_op
26
+ def keyword_queries
27
+ unless(@keyword_queries)
28
+ @keyword_queries = {}
29
+
30
+ return @keyword_queries unless @params[:search_field] == BlacklightAdvancedSearch.config[:url_key]
31
+
32
+ @config[:search_fields].each do | field_def |
33
+ key = field_def[:key]
34
+ if ! @params[ key.to_sym ].blank?
35
+ @keyword_queries[ key ] = @params[ key.to_sym ]
36
+ end
37
+ end
38
+ end
39
+ return @keyword_queries
40
+ end
41
+ # returns just advanced-type filters
42
+ def filters
43
+ unless (@filters)
44
+ @filters = {}
45
+ return @filters unless @params[:f_inclusive]
46
+ @params[:f_inclusive].each_pair do |field, value_hash|
47
+ value_hash.each_pair do |value, type|
48
+ @filters[field] ||= []
49
+ @filters[field] << value
50
+ end
51
+ end
52
+ end
53
+ return @filters
54
+ end
55
+
56
+ def empty?
57
+ filters.empty? && keyword_queries.empty?
58
+ end
59
+
60
+ end
61
+ end
@@ -0,0 +1,53 @@
1
+ module BlacklightAdvancedSearch::CatalogHelperOverride
2
+
3
+
4
+
5
+ def remove_advanced_keyword_query(field, my_params = params)
6
+ my_params = my_params.dup
7
+ my_params.delete(field)
8
+ return my_params
9
+ end
10
+
11
+ def remove_advanced_filter_group(field, my_params = params)
12
+ if (my_params[:f_inclusive])
13
+ my_params = my_params.dup
14
+ my_params[:f_inclusive] = my_params[:f_inclusive].dup
15
+ my_params[:f_inclusive].delete(field)
16
+ end
17
+ my_params
18
+ end
19
+
20
+ # Special display for facet limits that include adv search inclusive
21
+ # or limits.
22
+ def render_facet_limit(solr_field)
23
+ unless (@advanced_query && @advanced_query.filters.keys.include?( solr_field))
24
+ super(solr_field)
25
+ else
26
+ # our own display
27
+ render(:partial => "blacklight_advanced_search/facet_limit", :locals=> {:solr_field => solr_field})
28
+ end
29
+ end
30
+
31
+ def remove_advanced_facet_param(field, value, my_params = params)
32
+ my_params = my_params.dup
33
+ if (my_params[:f_inclusive] &&
34
+ my_params[:f_inclusive][field] &&
35
+ my_params[:f_inclusive][field].include?(value))
36
+
37
+ my_params[:f_inclusive] = my_params[:f_inclusive].dup
38
+ my_params[:f_inclusive][field] = my_params[:f_inclusive][field].dup
39
+ my_params[:f_inclusive][field].delete(value)
40
+
41
+ my_params[:f_inclusive].delete(field) if my_params[:f_inclusive][field].length == 0
42
+
43
+ my_params.delete(:f_inclusive) if my_params[:f_inclusive].length == 0
44
+ end
45
+
46
+ my_params.delete_if do |key, value|
47
+ [:page, :id, :counter, :commit].include?(key)
48
+ end
49
+
50
+ my_params
51
+ end
52
+
53
+ end