blacklight 7.12.0 → 7.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +109 -0
  3. data/.rubocop.yml +3 -0
  4. data/README.md +1 -1
  5. data/VERSION +1 -1
  6. data/app/assets/javascripts/blacklight/blacklight.js +4 -2
  7. data/app/components/blacklight/constraints_component.rb +14 -6
  8. data/app/components/blacklight/document/thumbnail_component.html.erb +1 -1
  9. data/app/components/blacklight/document/thumbnail_component.rb +1 -1
  10. data/app/components/blacklight/document_component.html.erb +1 -0
  11. data/app/components/blacklight/document_component.rb +14 -1
  12. data/app/components/blacklight/facet_field_component.html.erb +1 -0
  13. data/app/components/blacklight/facet_field_pagination_component.html.erb +4 -4
  14. data/app/components/blacklight/facet_field_pagination_component.rb +0 -4
  15. data/app/components/blacklight/hidden_search_state_component.rb +54 -0
  16. data/app/components/blacklight/search_bar_component.html.erb +10 -8
  17. data/app/components/blacklight/search_bar_component.rb +14 -1
  18. data/app/controllers/concerns/blacklight/catalog.rb +3 -3
  19. data/app/controllers/concerns/blacklight/search_context.rb +2 -2
  20. data/app/controllers/concerns/blacklight/searchable.rb +1 -1
  21. data/app/helpers/blacklight/blacklight_helper_behavior.rb +1 -1
  22. data/app/helpers/blacklight/component_helper_behavior.rb +1 -1
  23. data/app/helpers/blacklight/configuration_helper_behavior.rb +3 -9
  24. data/app/helpers/blacklight/facets_helper_behavior.rb +8 -2
  25. data/app/helpers/blacklight/hash_as_hidden_fields_helper_behavior.rb +2 -38
  26. data/app/helpers/blacklight/icon_helper_behavior.rb +1 -1
  27. data/app/helpers/blacklight/render_constraints_helper_behavior.rb +7 -5
  28. data/app/helpers/blacklight/render_partials_helper_behavior.rb +2 -2
  29. data/app/javascript/blacklight/button_focus.js +1 -0
  30. data/app/javascript/blacklight/modal.js +10 -4
  31. data/app/presenters/blacklight/document_presenter.rb +4 -0
  32. data/app/presenters/blacklight/facet_item_presenter.rb +7 -3
  33. data/app/presenters/blacklight/index_presenter.rb +2 -2
  34. data/app/presenters/blacklight/rendering/link_to_facet.rb +3 -1
  35. data/app/presenters/blacklight/show_presenter.rb +0 -4
  36. data/app/services/blacklight/search_service.rb +13 -11
  37. data/app/values/blacklight/types.rb +1 -1
  38. data/app/views/bookmarks/_tools.html.erb +1 -1
  39. data/app/views/catalog/_search_form.html.erb +1 -1
  40. data/app/views/catalog/index.json.jbuilder +3 -1
  41. data/blacklight.gemspec +5 -4
  42. data/lib/blacklight/configuration/facet_field.rb +7 -0
  43. data/lib/blacklight/configuration/fields.rb +1 -1
  44. data/lib/blacklight/configuration/search_field.rb +5 -0
  45. data/lib/blacklight/configuration/tool_config.rb +4 -0
  46. data/lib/blacklight/configuration/view_config.rb +12 -0
  47. data/lib/blacklight/nested_open_struct_with_hash_access.rb +1 -1
  48. data/lib/blacklight/search_builder.rb +13 -23
  49. data/lib/blacklight/search_state.rb +82 -70
  50. data/lib/blacklight/search_state/filter_field.rb +122 -0
  51. data/lib/blacklight/solr/repository.rb +3 -3
  52. data/lib/blacklight/solr/response.rb +1 -1
  53. data/lib/blacklight/solr/search_builder_behavior.rb +71 -51
  54. data/package.json +5 -1
  55. data/spec/components/blacklight/constraint_layout_component_spec.rb +1 -1
  56. data/spec/components/blacklight/document_component_spec.rb +17 -0
  57. data/spec/components/blacklight/hidden_search_state_component_spec.rb +24 -0
  58. data/spec/features/facets_spec.rb +2 -17
  59. data/spec/features/search_filters_spec.rb +0 -20
  60. data/spec/features/search_spec.rb +0 -5
  61. data/spec/helpers/blacklight/configuration_helper_behavior_spec.rb +1 -2
  62. data/spec/helpers/blacklight/hash_as_hidden_fields_behavior_spec.rb +1 -0
  63. data/spec/helpers/blacklight/url_helper_behavior_spec.rb +1 -0
  64. data/spec/lib/blacklight/configuration/view_config_spec.rb +15 -0
  65. data/spec/lib/blacklight/nested_open_struct_with_hash_access_spec.rb +9 -0
  66. data/spec/lib/blacklight/search_state/filter_field_spec.rb +125 -0
  67. data/spec/lib/blacklight/search_state_spec.rb +132 -3
  68. data/spec/models/blacklight/configuration_spec.rb +8 -0
  69. data/spec/models/blacklight/solr/response/facets_spec.rb +1 -1
  70. data/spec/models/blacklight/solr/search_builder_spec.rb +32 -2
  71. data/spec/spec_helper.rb +8 -3
  72. data/spec/test_app_templates/Gemfile.extra +1 -1
  73. data/spec/views/catalog/_document.html.erb_spec.rb +1 -0
  74. data/spec/views/catalog/_thumbnail.html.erb_spec.rb +2 -0
  75. data/tasks/blacklight.rake +3 -3
  76. metadata +50 -29
  77. data/.npmignore +0 -23
  78. data/.travis.yml +0 -40
@@ -46,6 +46,13 @@ module Blacklight
46
46
  # are a hash containing: label (a label to show the user in the facet interface), fq (a string passed into solr as an fq (when selected) or a facet.query)
47
47
  # @!attribute pivot
48
48
  # @return []
49
+ # @!attribute filter_query_builder
50
+ # @return [nil, #call] a Proc (or other object responding to #call) that receives as parameters: 1) the search builder, 2) this facet config
51
+ # and 3) the solr parameters hash. The Proc returns a string suitable for e.g. Solr's fq parameter, or a 2-element array of the string and a hash of additional
52
+ # parameters to include with the query (i.e. for referenced subqueries); note that implementations are responsible for ensuring
53
+ # the additional parameter keys are unique.
54
+ # @!attribute filter_class
55
+ # @ return [nil, Blacklight::SearchState::FilterField] a class that implements the `FilterField`'s' API to manage URL parameters for a facet
49
56
 
50
57
  ##
51
58
  # Rendering:
@@ -151,7 +151,7 @@ module Blacklight
151
151
  repository = repository_class.new(self)
152
152
  repository.reflect_fields
153
153
  rescue => e
154
- Blacklight.logger.warn "Error retrieving field metadata: #{e}"
154
+ Blacklight.logger&.warn "Error retrieving field metadata: #{e}"
155
155
  false
156
156
  end
157
157
 
@@ -3,6 +3,11 @@ module Blacklight
3
3
  class Configuration::SearchField < Blacklight::Configuration::Field
4
4
  # @!attribute include_in_simple_select
5
5
  # @!attribute qt
6
+ # @!attribute query_builder
7
+ # @return [nil, #call] a Proc (or other object responding to #call) that receives as parameters: 1) the search builder, 2) this search field,
8
+ # and 3) the solr_parameters hash. The Proc returns a string suitable for e.g. Solr's q parameter, or a 2-element array of the
9
+ # string and a hash of additional parameters to include with the query (i.e. for referenced subqueries); note that
10
+ # implementations are responsible for ensuring the additional parameter keys are unique.
6
11
 
7
12
  def normalize! blacklight_config = nil
8
13
  self.if = include_in_simple_select if self.if.nil?
@@ -2,5 +2,9 @@
2
2
  module Blacklight
3
3
  class Configuration::ToolConfig < OpenStructWithHashAccess
4
4
  # @!attribute partial
5
+
6
+ def name
7
+ super || key
8
+ end
5
9
  end
6
10
  end
@@ -17,6 +17,18 @@ class Blacklight::Configuration
17
17
  super || Blacklight::SearchBarPresenter
18
18
  end
19
19
 
20
+ def display_label(key)
21
+ I18n.t(
22
+ :"blacklight.search.view_title.#{key}",
23
+ default: [
24
+ :"blacklight.search.view.#{key}",
25
+ label,
26
+ title,
27
+ key.to_s.humanize
28
+ ]
29
+ )
30
+ end
31
+
20
32
  class Show < ViewConfig
21
33
  # @!attribute route
22
34
  # @return [Hash] Default route parameters for 'show' requests.
@@ -101,7 +101,7 @@ module Blacklight
101
101
 
102
102
  def set_default_proc!
103
103
  self.default_proc = lambda do |hash, key|
104
- hash[key] = nested_class.new
104
+ hash[key] = nested_class.new(key: key)
105
105
  end
106
106
  end
107
107
  end
@@ -8,7 +8,7 @@ module Blacklight
8
8
  class_attribute :default_processor_chain
9
9
  self.default_processor_chain = []
10
10
 
11
- attr_reader :processor_chain, :blacklight_params
11
+ attr_reader :processor_chain, :search_state, :blacklight_params
12
12
 
13
13
  # @overload initialize(scope)
14
14
  # @param [Object] scope scope the scope where the filter methods reside in.
@@ -27,15 +27,17 @@ module Blacklight
27
27
  end
28
28
 
29
29
  @blacklight_params = {}
30
+ @search_state = Blacklight::SearchState.new(@blacklight_params, @scope&.blacklight_config, @scope)
30
31
  @merged_params = {}
31
32
  @reverse_merged_params = {}
32
33
  end
33
34
 
34
35
  ##
35
36
  # Set the parameters to pass through the processor chain
36
- def with(blacklight_params = {})
37
+ def with(blacklight_params_or_search_state = {})
37
38
  params_will_change!
38
- @blacklight_params = blacklight_params.dup
39
+ @search_state = blacklight_params_or_search_state.is_a?(Blacklight::SearchState) ? blacklight_params_or_search_state : @search_state.reset(blacklight_params_or_search_state)
40
+ @blacklight_params = @search_state.params.dup
39
41
  self
40
42
  end
41
43
 
@@ -43,7 +45,8 @@ module Blacklight
43
45
  # Update the :q (query) parameter
44
46
  def where(conditions)
45
47
  params_will_change!
46
- @blacklight_params[:q] = conditions
48
+ @search_state = @search_state.reset(@search_state.params.merge(q: conditions))
49
+ @blacklight_params = @search_state.params.dup
47
50
  self
48
51
  end
49
52
 
@@ -52,7 +55,7 @@ module Blacklight
52
55
  def append(*addl_processor_chain)
53
56
  params_will_change!
54
57
  builder = self.class.new(processor_chain + addl_processor_chain, scope)
55
- .with(blacklight_params)
58
+ .with(search_state)
56
59
  .merge(@merged_params)
57
60
  .reverse_merge(@reverse_merged_params)
58
61
 
@@ -72,7 +75,7 @@ module Blacklight
72
75
  # chain are ignored as no-ops, rather than raising.
73
76
  def except(*except_processor_chain)
74
77
  builder = self.class.new(processor_chain - except_processor_chain, scope)
75
- .with(blacklight_params)
78
+ .with(search_state)
76
79
  .merge(@merged_params)
77
80
  .reverse_merge(@reverse_merged_params)
78
81
 
@@ -175,7 +178,7 @@ module Blacklight
175
178
  self.page = value
176
179
  return self
177
180
  end
178
- @page ||= blacklight_params[:page].blank? ? 1 : blacklight_params[:page].to_i
181
+ @page ||= search_state.page
179
182
  end
180
183
 
181
184
  def rows=(value)
@@ -191,8 +194,7 @@ module Blacklight
191
194
  end
192
195
  @rows ||= begin
193
196
  # user-provided parameters should override any default row
194
- r = [:rows, :per_page].map { |k| blacklight_params[k] }.reject(&:blank?).first
195
- r ||= blacklight_config.default_per_page
197
+ r = search_state.per_page
196
198
  # ensure we don't excede the max page size
197
199
  r.nil? ? nil : [r, blacklight_config.max_per_page].map(&:to_i).min
198
200
  end
@@ -220,22 +222,10 @@ module Blacklight
220
222
  # configured search values are passed through to the search.
221
223
  # @return [String] the field/fields to sort by
222
224
  def sort
223
- sort_field = if blacklight_params[:sort].blank?
224
- # no sort param provided, use default
225
- blacklight_config.default_sort_field
226
- else
227
- # check for sort field key
228
- blacklight_config.sort_fields[blacklight_params[:sort]]
229
- end
230
- return sort_field.sort if sort_field.present?
231
-
232
- Blacklight.logger.warn "Invalid sort field: '#{blacklight_params[:sort]}' was provided."
233
- nil
225
+ search_state.sort_field&.sort
234
226
  end
235
227
 
236
- def search_field
237
- blacklight_config.search_fields[blacklight_params[:search_field]]
238
- end
228
+ delegate :search_field, to: :search_state
239
229
 
240
230
  private
241
231
 
@@ -1,4 +1,7 @@
1
1
  # frozen_string_literal: true
2
+
3
+ require 'blacklight/search_state/filter_field'
4
+
2
5
  module Blacklight
3
6
  # This class encapsulates the search state as represented by the query
4
7
  # parameters namely: :f, :q, :page, :per_page and, :sort
@@ -78,7 +81,9 @@ module Blacklight
78
81
  deprecation_deprecate :[]
79
82
 
80
83
  def has_constraints?
81
- !(query_param.blank? && filter_params.blank?)
84
+ Deprecation.silence(Blacklight::SearchState) do
85
+ !(query_param.blank? && filter_params.blank? && filters.blank?)
86
+ end
82
87
  end
83
88
 
84
89
  def query_param
@@ -88,11 +93,18 @@ module Blacklight
88
93
  def filter_params
89
94
  params[:f] || {}
90
95
  end
96
+ deprecation_deprecate filter_params: 'Use #filters instead'
91
97
 
98
+ # @return [Blacklight::SearchState]
92
99
  def reset(params = nil)
93
100
  self.class.new(params || ActionController::Parameters.new, blacklight_config, controller)
94
101
  end
95
102
 
103
+ # @return [Blacklight::SearchState]
104
+ def reset_search(additional_params = {})
105
+ reset(reset_search_params.merge(additional_params))
106
+ end
107
+
96
108
  ##
97
109
  # Extension point for downstream applications
98
110
  # to provide more interesting routing to
@@ -115,23 +127,30 @@ module Blacklight
115
127
  p
116
128
  end
117
129
 
130
+ def filters
131
+ @filters ||= blacklight_config.facet_fields.each_value.map do |value|
132
+ f = filter(value)
133
+
134
+ f if f.any?
135
+ end.compact
136
+ end
137
+
138
+ def filter(field_key_or_field)
139
+ field = field_key_or_field if field_key_or_field.is_a? Blacklight::Configuration::Field
140
+ field ||= blacklight_config.facet_fields[field_key_or_field]
141
+ field ||= Blacklight::Configuration::NullField.new(key: field_key_or_field)
142
+
143
+ (field.filter_class || FilterField).new(field, self)
144
+ end
145
+
118
146
  # adds the value and/or field to params[:f]
119
147
  # Does NOT remove request keys and otherwise ensure that the hash
120
148
  # is suitable for a redirect. See
121
149
  # add_facet_params_and_redirect
122
150
  def add_facet_params(field, item)
123
- p = reset_search_params
124
-
125
- add_facet_param(p, field, item)
126
-
127
- if item && item.respond_to?(:fq) && item.fq
128
- Array(item.fq).each do |f, v|
129
- add_facet_param(p, f, v)
130
- end
131
- end
132
-
133
- p
151
+ filter(field).add(item).params
134
152
  end
153
+ deprecation_deprecate add_facet_params: 'Use filter(field).add(item) instead'
135
154
 
136
155
  # Used in catalog/facet action, facets.rb view, for a click
137
156
  # on a facet value. Add on the facet params to existing
@@ -141,7 +160,9 @@ module Blacklight
141
160
  # Change the action to 'index' to send them back to
142
161
  # catalog/index with their new facet choice.
143
162
  def add_facet_params_and_redirect(field, item)
144
- new_params = add_facet_params(field, item)
163
+ new_params = Deprecation.silence(self.class) do
164
+ add_facet_params(field, item)
165
+ end
145
166
 
146
167
  # Delete any request params from facet-specific action, needed
147
168
  # to redir to index action properly.
@@ -158,45 +179,18 @@ module Blacklight
158
179
  # @param [String] field
159
180
  # @param [String] item
160
181
  def remove_facet_params(field, item)
161
- if item.respond_to? :field
162
- field = item.field
163
- end
164
-
165
- facet_config = facet_configuration_for_field(field)
166
-
167
- url_field = facet_config.key
168
-
169
- value = facet_value_for_facet_item(item)
170
-
171
- p = reset_search_params
172
- # need to dup the facet values too,
173
- # if the values aren't dup'd, then the values
174
- # from the session will get remove in the show view...
175
- p[:f] = (p[:f] || {}).dup
176
- p[:f][url_field] = (p[:f][url_field] || []).dup
177
-
178
- collection = p[:f][url_field]
179
- # collection should be an array, because we link to ?f[key][]=value,
180
- # however, Facebook (and maybe some other PHP tools) tranform that parameters
181
- # into ?f[key][0]=value, which Rails interprets as a Hash.
182
- if collection.is_a? Hash
183
- collection = collection.values
184
- end
185
- p[:f][url_field] = collection - [value]
186
- p[:f].delete(url_field) if p[:f][url_field].empty?
187
- p.delete(:f) if p[:f].empty?
188
- p
182
+ filter(field).remove(item).params
189
183
  end
184
+ deprecation_deprecate remove_facet_params: 'Use filter(field).remove(item) instead'
190
185
 
191
186
  def has_facet?(config, value: nil)
192
- facet = params&.dig(:f, config.key)
193
-
194
187
  if value
195
- (facet || []).include? value
188
+ filter(config).include?(value)
196
189
  else
197
- facet.present?
190
+ filter(config).any?
198
191
  end
199
192
  end
193
+ deprecation_deprecate has_facet?: 'Use filter(field).include?(value) or .any? instead'
200
194
 
201
195
  # Merge the source params with the params_to_merge hash
202
196
  # @param [Hash] params_to_merge to merge into above
@@ -217,44 +211,62 @@ module Blacklight
217
211
  Parameters.sanitize(my_params)
218
212
  end
219
213
 
220
- private
214
+ def page
215
+ [params[:page].to_i, 1].max
216
+ end
221
217
 
222
- ##
223
- # Reset any search parameters that store search context
224
- # and need to be reset when e.g. constraints change
225
- # @return [ActionController::Parameters]
226
- def reset_search_params
227
- Parameters.sanitize(params).except(:page, :counter)
218
+ def per_page
219
+ params[:rows].presence&.to_i ||
220
+ params[:per_page].presence&.to_i ||
221
+ blacklight_config.default_per_page
228
222
  end
229
223
 
230
- # TODO: this code is duplicated in Blacklight::FacetsHelperBehavior
231
- def facet_value_for_facet_item item
232
- if item.respond_to? :value
233
- item.value
224
+ def sort_field
225
+ if sort_field_key.blank?
226
+ # no sort param provided, use default
227
+ blacklight_config.default_sort_field
234
228
  else
235
- item
229
+ # check for sort field key
230
+ blacklight_config.sort_fields[sort_field_key]
236
231
  end
237
232
  end
238
233
 
239
- def add_facet_param(p, field, item)
240
- if item.respond_to? :field
241
- field = item.field
242
- end
234
+ def search_field
235
+ blacklight_config.search_fields[search_field_key]
236
+ end
243
237
 
244
- facet_config = facet_configuration_for_field(field)
238
+ def facet_page
239
+ [params[facet_request_keys[:page]].to_i, 1].max
240
+ end
245
241
 
246
- url_field = facet_config.key
242
+ def facet_sort
243
+ params[facet_request_keys[:sort]]
244
+ end
247
245
 
248
- value = facet_value_for_facet_item(item)
246
+ def facet_prefix
247
+ params[facet_request_keys[:prefix]]
248
+ end
249
249
 
250
- p[:f] = (p[:f] || {}).dup # the command above is not deep in rails3, !@#$!@#$
251
- p[:f][url_field] = (p[:f][url_field] || []).dup
250
+ private
252
251
 
253
- if facet_config.single && p[:f][url_field].present?
254
- p[:f][url_field] = []
255
- end
252
+ def search_field_key
253
+ params[:search_field]
254
+ end
255
+
256
+ def sort_field_key
257
+ params[:sort]
258
+ end
259
+
260
+ def facet_request_keys
261
+ blacklight_config.facet_paginator_class.request_keys
262
+ end
256
263
 
257
- p[:f][url_field].push(value)
264
+ ##
265
+ # Reset any search parameters that store search context
266
+ # and need to be reset when e.g. constraints change
267
+ # @return [ActionController::Parameters]
268
+ def reset_search_params
269
+ Parameters.sanitize(params).except(:page, :counter)
258
270
  end
259
271
  end
260
272
  end
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Blacklight
4
+ class SearchState
5
+ # Modeling access to filter query parameters
6
+ class FilterField
7
+ # @param [Blacklight::Configuration::FacetField] config
8
+ attr_reader :config
9
+
10
+ # @param [Blacklight::SearchState] search_state
11
+ attr_reader :search_state
12
+
13
+ # @return [String,Symbol]
14
+ delegate :key, to: :config
15
+
16
+ # @param [Blacklight::Configuration::FacetField] config
17
+ # @param [Blacklight::SearchState] search_state
18
+ def initialize(config, search_state)
19
+ @config = config
20
+ @search_state = search_state
21
+ end
22
+
23
+ # @param [String,#value] a filter item to add to the url
24
+ # @return [Blacklight::SearchState] new state
25
+ def add(item)
26
+ new_state = search_state.reset_search
27
+
28
+ if item.respond_to?(:fq)
29
+ Array(item.fq).each do |f, v|
30
+ new_state = new_state.filter(f).add(v)
31
+ end
32
+ end
33
+
34
+ if item.respond_to?(:field) && item.field != key
35
+ return new_state.filter(item.field).add(item)
36
+ end
37
+
38
+ params = new_state.params
39
+ value = as_url_parameter(item)
40
+
41
+ # value could be a string
42
+ params[param] = (params[param] || {}).dup
43
+
44
+ if config.single
45
+ params[param][key] = [value]
46
+ else
47
+ params[param][key] = Array(params[param][key] || []).dup
48
+ params[param][key].push(value)
49
+ end
50
+
51
+ new_state.reset(params)
52
+ end
53
+
54
+ # @param [String,#value] a filter to remove from the url
55
+ # @return [Blacklight::SearchState] new state
56
+ def remove(item)
57
+ new_state = search_state.reset_search
58
+ if item.respond_to?(:field) && item.field != key
59
+ return new_state.filter(item.field).remove(item)
60
+ end
61
+
62
+ params = new_state.params
63
+ value = as_url_parameter(item)
64
+
65
+ # need to dup the facet values too,
66
+ # if the values aren't dup'd, then the values
67
+ # from the session will get remove in the show view...
68
+ params[param] = (params[param] || {}).dup
69
+ params[param][key] = (params[param][key] || []).dup
70
+
71
+ collection = params[param][key]
72
+ # collection should be an array, because we link to ?f[key][]=value,
73
+ # however, Facebook (and maybe some other PHP tools) tranform that parameters
74
+ # into ?f[key][0]=value, which Rails interprets as a Hash.
75
+ if collection.is_a? Hash
76
+ Deprecation.warn(self, 'Normalizing parameters in FilterField#remove is deprecated')
77
+ collection = collection.values
78
+ end
79
+ params[param][key] = collection - Array(value)
80
+ params[param].delete(key) if params[param][key].empty?
81
+ params.delete(param) if params[param].empty?
82
+
83
+ new_state.reset(params)
84
+ end
85
+
86
+ # @return [Array] an array of applied filters
87
+ def values
88
+ params = search_state.params
89
+ Array(params.dig(param, key)) || []
90
+ end
91
+ delegate :any?, to: :values
92
+
93
+ # @param [String,#value] a filter to remove from the url
94
+ # @return [Boolean] whether the provided filter is currently applied/selected
95
+ def include?(item)
96
+ if item.respond_to?(:field) && item.field != key
97
+ return search_state.filter(item.field).selected?(item)
98
+ end
99
+
100
+ value = as_url_parameter(item)
101
+ params = search_state.params
102
+
103
+ (params.dig(param, key) || []).include?(value)
104
+ end
105
+
106
+ private
107
+
108
+ def param
109
+ :f
110
+ end
111
+
112
+ # TODO: this code is duplicated in Blacklight::FacetsHelperBehavior
113
+ def as_url_parameter(item)
114
+ if item.respond_to? :value
115
+ item.value
116
+ else
117
+ item
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end