blacklight 7.7.0 → 7.8.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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/.docker/app/Dockerfile +26 -0
  3. data/.docker/app/entrypoint.sh +6 -0
  4. data/.env +5 -0
  5. data/.rubocop_todo.yml +13 -13
  6. data/.travis.yml +15 -23
  7. data/Gemfile +4 -1
  8. data/README.md +4 -0
  9. data/VERSION +1 -1
  10. data/app/assets/stylesheets/blacklight/_pagination.scss +4 -0
  11. data/app/components/blacklight/constraint_layout_component.html.erb +21 -0
  12. data/app/components/blacklight/constraint_layout_component.rb +16 -0
  13. data/app/components/blacklight/facet_field_component.html.erb +25 -0
  14. data/app/components/blacklight/facet_field_component.rb +11 -0
  15. data/app/components/blacklight/facet_field_list_component.html.erb +18 -0
  16. data/app/components/blacklight/facet_field_list_component.rb +22 -0
  17. data/app/components/blacklight/facet_field_no_layout_component.rb +13 -0
  18. data/app/components/blacklight/facet_item_component.rb +120 -0
  19. data/app/helpers/blacklight/catalog_helper_behavior.rb +2 -2
  20. data/app/helpers/blacklight/facets_helper_behavior.rb +84 -48
  21. data/app/helpers/blacklight/render_constraints_helper_behavior.rb +64 -33
  22. data/app/javascript/blacklight/modal.js +1 -1
  23. data/app/models/concerns/blacklight/document/extensions.rb +3 -0
  24. data/app/models/concerns/blacklight/document/semantic_fields.rb +0 -4
  25. data/app/presenters/blacklight/facet_field_presenter.rb +57 -0
  26. data/app/presenters/blacklight/facet_item_presenter.rb +81 -0
  27. data/app/views/catalog/_citation.html.erb +1 -1
  28. data/app/views/catalog/_constraints.html.erb +1 -1
  29. data/app/views/catalog/_constraints_element.html.erb +5 -24
  30. data/app/views/catalog/_email_form.html.erb +1 -1
  31. data/app/views/catalog/_facet_layout.html.erb +8 -17
  32. data/app/views/catalog/_facet_limit.html.erb +3 -12
  33. data/app/views/catalog/_facet_pagination.html.erb +2 -2
  34. data/app/views/catalog/_facet_pivot.html.erb +4 -4
  35. data/app/views/catalog/_sms_form.html.erb +1 -1
  36. data/blacklight.gemspec +1 -0
  37. data/config/locales/blacklight.ar.yml +29 -25
  38. data/docker-compose.yml +35 -0
  39. data/lib/blacklight/engine.rb +2 -6
  40. data/lib/blacklight/search_state.rb +32 -0
  41. data/lib/blacklight/solr/response/facets.rb +2 -0
  42. data/lib/generators/blacklight/assets_generator.rb +10 -0
  43. data/spec/{views/catalog/_constraints_element.html.erb_spec.rb → components/blacklight/constraint_layout_component_spec.rb} +21 -11
  44. data/spec/components/blacklight/facet_field_list_component_spec.rb +108 -0
  45. data/spec/components/blacklight/facet_item_component_spec.rb +50 -0
  46. data/spec/features/facets_spec.rb +1 -1
  47. data/spec/helpers/blacklight/facets_helper_behavior_spec.rb +24 -12
  48. data/spec/helpers/blacklight/render_constraints_helper_behavior_spec.rb +4 -23
  49. data/spec/lib/blacklight/search_state_spec.rb +38 -0
  50. data/spec/models/blacklight/solr/response/facets_spec.rb +30 -1
  51. data/spec/presenters/blacklight/facet_field_presenter_spec.rb +109 -0
  52. data/spec/presenters/blacklight/facet_item_presenter_spec.rb +92 -0
  53. data/spec/spec_helper.rb +2 -0
  54. data/spec/support/presenter_test_helpers.rb +11 -0
  55. data/spec/views/catalog/_facet_group.html.erb_spec.rb +1 -0
  56. data/tasks/blacklight.rake +30 -23
  57. metadata +43 -5
@@ -151,7 +151,7 @@ module Blacklight::CatalogHelperBehavior
151
151
  # @return [String]
152
152
  def render_document_sidebar_partial(document = nil)
153
153
  unless document
154
- Deprecation.warn(self, 'render_document_sidebar_partial expects one argument ' /
154
+ Deprecation.warn(self, 'render_document_sidebar_partial expects one argument ' \
155
155
  '(@document) and you passed none. This behavior will be removed in version 8')
156
156
  document = @document
157
157
  end
@@ -277,7 +277,7 @@ module Blacklight::CatalogHelperBehavior
277
277
  facet_config = facet_configuration_for_field(facet)
278
278
  filter_label = facet_field_label(facet_config.key)
279
279
  filter_value = if values.size < 3
280
- values.map { |value| facet_display_value(facet, value) }.to_sentence
280
+ values.map { |value| facet_item_presenter(facet_config, value, facet).label }.to_sentence
281
281
  else
282
282
  t('blacklight.search.page_title.many_constraint_values', values: values.size)
283
283
  end
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
  module Blacklight::FacetsHelperBehavior
3
+ extend Deprecation
4
+ self.deprecation_horizon = 'blacklight 8.0'
5
+
3
6
  include Blacklight::Facet
4
7
 
5
8
  ##
@@ -14,7 +17,9 @@ module Blacklight::FacetsHelperBehavior
14
17
  '8.0.0')
15
18
  response = @response
16
19
  end
17
- facets_from_request(fields, response).any? { |display_facet| should_render_facet?(display_facet) }
20
+ Deprecation.silence(Blacklight::FacetsHelperBehavior) do
21
+ facets_from_request(fields, response).any? { |display_facet| should_render_facet?(display_facet) }
22
+ end
18
23
  end
19
24
 
20
25
  ##
@@ -58,8 +63,23 @@ module Blacklight::FacetsHelperBehavior
58
63
  # @return [String]
59
64
  def render_facet_limit(display_facet, options = {})
60
65
  field_config = facet_configuration_for_field(display_facet.name)
61
- return unless should_render_facet?(display_facet, field_config)
62
66
 
67
+ if field_config.component
68
+ component = field_config.component == true ? Blacklight::FacetFieldListComponent : field_config.component
69
+ return render(
70
+ component.new(
71
+ facet_field: facet_field_presenter(field_config, display_facet),
72
+ layout: (params[:action] == 'facet' ? false : options[:layout])
73
+ )
74
+ )
75
+ end
76
+
77
+ Deprecation.warn(Blacklight::FacetsHelperBehavior, 'Calling #render_facet_limit on a non-componentized'\
78
+ ' facet is deprecated and will be removed in Blacklight 8')
79
+
80
+ Deprecation.silence(Blacklight::FacetsHelperBehavior) do
81
+ return unless should_render_facet?(display_facet, field_config)
82
+ end
63
83
  options = options.dup
64
84
  options[:partial] ||= facet_partial_name(display_facet)
65
85
  options[:layout] ||= "facet_layout" unless options.key?(:layout)
@@ -76,12 +96,21 @@ module Blacklight::FacetsHelperBehavior
76
96
  # removes any elements where render_facet_item returns a nil value. This enables an application
77
97
  # to filter undesireable facet items so they don't appear in the UI
78
98
  def render_facet_limit_list(paginator, facet_field, wrapping_element = :li)
79
- safe_join(paginator.items.map { |item| render_facet_item(facet_field, item) }.compact.map { |item| content_tag(wrapping_element, item) })
99
+ facet_config ||= facet_configuration_for_field(facet_field)
100
+ component = facet_config.fetch(:item_component, Blacklight::FacetItemComponent)
101
+
102
+ collection = paginator.items.map do |item|
103
+ facet_item_presenter(facet_config, item, facet_field)
104
+ end
105
+
106
+ render(component.with_collection(collection, wrapping_element: wrapping_element))
80
107
  end
108
+ deprecation_deprecate :render_facet_limit_list
81
109
 
82
110
  ##
83
111
  # Renders a single facet item
84
112
  def render_facet_item(facet_field, item)
113
+ deprecated_method(:render_facet_item)
85
114
  if facet_in_params?(facet_field, item.value)
86
115
  render_selected_facet_value(facet_field, item)
87
116
  else
@@ -104,6 +133,7 @@ module Blacklight::FacetsHelperBehavior
104
133
  facet_config ||= facet_configuration_for_field(display_facet.name)
105
134
  should_render_field?(facet_config, display_facet)
106
135
  end
136
+ deprecation_deprecate :should_render_facet?
107
137
 
108
138
  ##
109
139
  # Determine whether a facet should be rendered as collapsed or not.
@@ -114,8 +144,11 @@ module Blacklight::FacetsHelperBehavior
114
144
  # @param [Blacklight::Configuration::FacetField] facet_field
115
145
  # @return [Boolean]
116
146
  def should_collapse_facet? facet_field
117
- !facet_field_in_params?(facet_field.key) && facet_field.collapse
147
+ Deprecation.silence(Blacklight::FacetsHelperBehavior) do
148
+ !facet_field_in_params?(facet_field.key) && facet_field.collapse
149
+ end
118
150
  end
151
+ deprecation_deprecate :should_collapse_facet?
119
152
 
120
153
  ##
121
154
  # The name of the partial to use to render a facet field.
@@ -130,6 +163,11 @@ module Blacklight::FacetsHelperBehavior
130
163
  name ||= "facet_pivot" if config.pivot
131
164
  name || "facet_limit"
132
165
  end
166
+ deprecation_deprecate :facet_partial_name
167
+
168
+ def facet_field_presenter(facet_config, display_facet)
169
+ Blacklight::FacetFieldPresenter.new(facet_config, display_facet, self)
170
+ end
133
171
 
134
172
  ##
135
173
  # Standard display of a facet value in a list. Used in both _facets sidebar
@@ -142,13 +180,9 @@ module Blacklight::FacetsHelperBehavior
142
180
  # @option options [Boolean] :suppress_link display the facet, but don't link to it
143
181
  # @return [String]
144
182
  def render_facet_value(facet_field, item, options = {})
145
- path = path_for_facet(facet_field, item)
146
- content_tag(:span, class: "facet-label") do
147
- link_to_unless(options[:suppress_link],
148
- facet_display_value(facet_field, item),
149
- path,
150
- class: "facet-select")
151
- end + render_facet_count(item.hits)
183
+ deprecated_method(:render_facet_value)
184
+ facet_config = facet_configuration_for_field(facet_field)
185
+ facet_item_component(facet_config, item, facet_field, **options).render_facet_value
152
186
  end
153
187
 
154
188
  ##
@@ -158,12 +192,9 @@ module Blacklight::FacetsHelperBehavior
158
192
  # @return [String]
159
193
  def path_for_facet(facet_field, item, path_options = {})
160
194
  facet_config = facet_configuration_for_field(facet_field)
161
- if facet_config.url_method
162
- send(facet_config.url_method, facet_field, item)
163
- else
164
- search_action_path(search_state.add_facet_params_and_redirect(facet_field, item).merge(path_options))
165
- end
195
+ facet_item_presenter(facet_config, item, facet_field).href(path_options)
166
196
  end
197
+ deprecation_deprecate :path_for_facet
167
198
 
168
199
  ##
169
200
  # Standard display of a SELECTED facet value (e.g. without a link and with a remove button)
@@ -171,15 +202,9 @@ module Blacklight::FacetsHelperBehavior
171
202
  # @param [Blacklight::Solr::Response::Facets::FacetField] facet_field
172
203
  # @param [String] item
173
204
  def render_selected_facet_value(facet_field, item)
174
- remove_href = search_action_path(search_state.remove_facet_params(facet_field, item))
175
- content_tag(:span, class: "facet-label") do
176
- content_tag(:span, facet_display_value(facet_field, item), class: "selected") +
177
- # remove link
178
- link_to(remove_href, class: "remove") do
179
- content_tag(:span, '✖', class: "remove-icon") +
180
- content_tag(:span, '[remove]', class: 'sr-only')
181
- end
182
- end + render_facet_count(item.hits, classes: ["selected"])
205
+ deprecated_method(:render_selected_facet_value)
206
+ facet_config = facet_configuration_for_field(facet_field)
207
+ facet_item_component(facet_config, item, facet_field).render_selected_facet_value
183
208
  end
184
209
 
185
210
  ##
@@ -191,18 +216,22 @@ module Blacklight::FacetsHelperBehavior
191
216
  # @option options [Array<String>] an array of classes to add to count span.
192
217
  # @return [String]
193
218
  def render_facet_count(num, options = {})
219
+ deprecated_method(:render_facet_count)
194
220
  classes = (options[:classes] || []) << "facet-count"
195
221
  content_tag("span", t('blacklight.search.facets.count', number: number_with_delimiter(num)), class: classes)
196
222
  end
197
223
 
198
224
  ##
199
225
  # Are any facet restrictions for a field in the query parameters?
200
- #
226
+ # @private
201
227
  # @param [String] field
202
228
  # @return [Boolean]
203
229
  def facet_field_in_params? field
204
- facet_params(field).present?
230
+ config = facet_configuration_for_field(field)
231
+ search_state.has_facet? config
205
232
  end
233
+ # Left undeprecated for the sake of temporary backwards compatibility
234
+ # deprecation_deprecate :facet_field_in_params?
206
235
 
207
236
  ##
208
237
  # Check if the query parameters have the given facet field with the
@@ -212,18 +241,19 @@ module Blacklight::FacetsHelperBehavior
212
241
  # @param [String] item facet value
213
242
  # @return [Boolean]
214
243
  def facet_in_params?(field, item)
215
- value = facet_value_for_facet_item(item)
216
-
217
- (facet_params(field) || []).include? value
244
+ config = facet_configuration_for_field(field)
245
+ search_state.has_facet? config, value: facet_value_for_facet_item(item)
218
246
  end
247
+ deprecation_deprecate :facet_in_params?
219
248
 
220
249
  ##
221
250
  # Get the values of the facet set in the blacklight query string
222
251
  def facet_params field
223
252
  config = facet_configuration_for_field(field)
224
253
 
225
- params[:f][config.key] if params[:f]
254
+ search_state.params.dig(:f, config.key)
226
255
  end
256
+ deprecation_deprecate :facet_params
227
257
 
228
258
  ##
229
259
  # Get the displayable version of a facet's value
@@ -231,30 +261,17 @@ module Blacklight::FacetsHelperBehavior
231
261
  # @param [Object] field
232
262
  # @param [String] item value
233
263
  # @return [String]
264
+ # @deprecated
234
265
  def facet_display_value field, item
266
+ deprecated_method(:facet_display_value)
235
267
  facet_config = facet_configuration_for_field(field)
236
-
237
- value = if item.respond_to? :label
238
- item.label
239
- else
240
- facet_value_for_facet_item(item)
241
- end
242
-
243
- if facet_config.helper_method
244
- send facet_config.helper_method, value
245
- elsif facet_config.query && facet_config.query[value]
246
- facet_config.query[value][:label]
247
- elsif facet_config.date
248
- localization_options = facet_config.date == true ? {} : facet_config.date
249
- l(Time.zone.parse(value), localization_options)
250
- else
251
- value
252
- end
268
+ facet_item_presenter(facet_config, item, field).label
253
269
  end
254
270
 
255
271
  def facet_field_id facet_field
256
272
  "facet-#{facet_field.key.parameterize}"
257
273
  end
274
+ deprecation_deprecate :facet_field_id
258
275
 
259
276
  private
260
277
 
@@ -265,4 +282,23 @@ module Blacklight::FacetsHelperBehavior
265
282
  item
266
283
  end
267
284
  end
285
+
286
+ def facet_item_presenter(facet_config, facet_item, facet_field)
287
+ Blacklight::FacetItemPresenter.new(facet_item, facet_config, self, facet_field)
288
+ end
289
+
290
+ def facet_item_component(facet_config, facet_item, facet_field, **args)
291
+ component = facet_config.fetch(:item_component, Blacklight::FacetItemComponent)
292
+ component.new(facet_item: facet_item_presenter(facet_config, facet_item, facet_field), **args).with_view_context(self)
293
+ end
294
+
295
+ # We can't use .deprecation_deprecate here, because the new components need to
296
+ # see the originally defined location for these methods in order to properly
297
+ # call back into the helpers for backwards compatibility
298
+ def deprecated_method(method_name)
299
+ Deprecation.warn(Blacklight::FacetsHelperBehavior,
300
+ Deprecation.deprecated_method_warning(Blacklight::FacetsHelperBehavior,
301
+ method_name, {}),
302
+ caller)
303
+ end
268
304
  end
@@ -6,14 +6,19 @@
6
6
  # Includes methods for rendering contraints graphically on the
7
7
  # search results page (render_constraints(_*))
8
8
  module Blacklight::RenderConstraintsHelperBehavior
9
+ extend Deprecation
10
+ self.deprecation_horizon = 'blacklight 8.0'
11
+
9
12
  ##
10
13
  # Check if the query has any constraints defined (a query, facet, etc)
11
14
  #
12
15
  # @param [Hash] localized_params query parameters
13
16
  # @return [Boolean]
14
- def query_has_constraints?(localized_params = params)
15
- !(localized_params[:q].blank? && localized_params[:f].blank?)
17
+ def query_has_constraints?(params_or_search_state = search_state)
18
+ search_state = convert_to_search_state(params_or_search_state)
19
+ search_state.has_constraints?
16
20
  end
21
+ deprecation_deprecate :query_has_constraints?
17
22
 
18
23
  ##
19
24
  # Render the actual constraints, not including header or footer
@@ -21,8 +26,16 @@ module Blacklight::RenderConstraintsHelperBehavior
21
26
  #
22
27
  # @param [Hash] localized_params query parameters
23
28
  # @return [String]
24
- def render_constraints(localized_params = params)
25
- render_constraints_query(localized_params) + render_constraints_filters(localized_params)
29
+ def render_constraints(localized_params = params, local_search_state = search_state)
30
+ params_or_search_state = if localized_params != params
31
+ localized_params
32
+ else
33
+ local_search_state
34
+ end
35
+
36
+ Deprecation.silence(Blacklight::RenderConstraintsHelperBehavior) do
37
+ render_constraints_query(params_or_search_state) + render_constraints_filters(params_or_search_state)
38
+ end
26
39
  end
27
40
 
28
41
  ##
@@ -30,15 +43,20 @@ module Blacklight::RenderConstraintsHelperBehavior
30
43
  #
31
44
  # @param [ActionController::Parameters] localized_params query parameters
32
45
  # @return [String]
33
- def render_constraints_query(localized_params = params)
46
+ def render_constraints_query(params_or_search_state = search_state)
47
+ search_state = convert_to_search_state(params_or_search_state)
48
+
34
49
  # So simple don't need a view template, we can just do it here.
35
- return "".html_safe if localized_params[:q].blank?
50
+ return "".html_safe if search_state.query_param.blank?
36
51
 
37
- render_constraint_element(constraint_query_label(localized_params),
38
- localized_params[:q],
39
- classes: ["query"],
40
- remove: remove_constraint_url(localized_params))
52
+ Deprecation.silence(Blacklight::RenderConstraintsHelperBehavior) do
53
+ render_constraint_element(constraint_query_label(search_state),
54
+ search_state.query_param,
55
+ classes: ["query"],
56
+ remove: remove_constraint_url(search_state))
57
+ end
41
58
  end
59
+ deprecation_deprecate :render_constraints_query
42
60
 
43
61
  ##
44
62
  # Provide a url for removing a particular constraint. This can be overriden
@@ -47,52 +65,53 @@ module Blacklight::RenderConstraintsHelperBehavior
47
65
  #
48
66
  # @param [ActionController::Parameters] localized_params query parameters
49
67
  # @return [String]
50
- def remove_constraint_url(localized_params)
51
- scope = localized_params.delete(:route_set) || self
52
-
53
- unless localized_params.is_a? ActionController::Parameters
54
- localized_params = ActionController::Parameters.new(localized_params)
55
- end
68
+ def remove_constraint_url(params_or_search_state = search_state)
69
+ search_state = convert_to_search_state(params_or_search_state)
56
70
 
57
- options = localized_params.merge(q: nil, action: 'index')
58
- options.permit!
59
- scope.url_for(options)
71
+ search_action_path(search_state.remove_query_params)
60
72
  end
73
+ deprecation_deprecate :remove_constraint_url
61
74
 
62
75
  ##
63
76
  # Render the facet constraints
64
77
  # @param [Hash] localized_params query parameters
65
78
  # @return [String]
66
- def render_constraints_filters(localized_params = params)
67
- return "".html_safe unless localized_params[:f]
79
+ def render_constraints_filters(params_or_search_state = search_state)
80
+ search_state = convert_to_search_state(params_or_search_state)
68
81
 
69
- path = controller.search_state_class.new(localized_params, blacklight_config, controller)
70
- content = []
71
- localized_params[:f].each_pair do |facet, values|
72
- content << render_filter_element(facet, values, path)
73
- end
82
+ return "".html_safe if search_state.filter_params.blank?
74
83
 
75
- safe_join(content.flatten, "\n")
84
+ Deprecation.silence(Blacklight::RenderConstraintsHelperBehavior) do
85
+ safe_join(search_state.filter_params.each_pair.map do |facet, values|
86
+ render_filter_element(facet, values, search_state)
87
+ end, "\n")
88
+ end
76
89
  end
90
+ deprecation_deprecate :render_constraints_filters
77
91
 
78
92
  ##
79
93
  # Render a single facet's constraint
80
94
  # @param [String] facet field
81
95
  # @param [Array<String>] values selected facet values
82
- # @param [Blacklight::SearchState] path query parameters
96
+ # @param [Blacklight::SearchState] path query parameters (unused)
83
97
  # @return [String]
84
- def render_filter_element(facet, values, path)
98
+ def render_filter_element(facet, values, search_state)
85
99
  facet_config = facet_configuration_for_field(facet)
86
100
 
87
101
  safe_join(Array(values).map do |val|
88
102
  next if val.blank? # skip empty string
89
103
 
90
- render_constraint_element(facet_field_label(facet_config.key),
91
- facet_display_value(facet, val),
92
- remove: search_action_path(path.remove_facet_params(facet, val)),
93
- classes: ["filter", "filter-" + facet.parameterize])
104
+ presenter = facet_item_presenter(facet_config, val, facet)
105
+
106
+ Deprecation.silence(Blacklight::RenderConstraintsHelperBehavior) do
107
+ render_constraint_element(facet_field_label(facet_config.key),
108
+ presenter.label,
109
+ remove: presenter.remove_href(search_state),
110
+ classes: ["filter", "filter-" + facet.parameterize])
111
+ end
94
112
  end, "\n")
95
113
  end
114
+ deprecation_deprecate :render_filter_element
96
115
 
97
116
  # Render a label/value constraint on the screen. Can be called
98
117
  # by plugins and such to get application-defined rendering.
@@ -111,4 +130,16 @@ module Blacklight::RenderConstraintsHelperBehavior
111
130
  def render_constraint_element(label, value, options = {})
112
131
  render(partial: "catalog/constraints_element", locals: { label: label, value: value, options: options })
113
132
  end
133
+ deprecation_deprecate :render_constraint_element
134
+
135
+ private
136
+
137
+ def convert_to_search_state(params_or_search_state)
138
+ if params_or_search_state.is_a? Blacklight::SearchState
139
+ params_or_search_state
140
+ else
141
+ # deprecated
142
+ controller.search_state_class.new(params_or_search_state, blacklight_config, controller)
143
+ end
144
+ end
114
145
  end
@@ -44,7 +44,7 @@
44
44
 
45
45
  <div class="modal-body">
46
46
  <p>Some message</p>
47
- <%= link_to "This result will still be within modal", some_link, data: { blacklight: "preserve" } %>
47
+ <%= link_to "This result will still be within modal", some_link, data: { blacklight_modal: "preserve" } %>
48
48
  </div>
49
49
 
50
50
 
@@ -32,6 +32,9 @@ module Blacklight::Document::Extensions
32
32
  module ClassMethods
33
33
  attr_writer :registered_extensions
34
34
 
35
+ # Returns array of hashes of registered extensions. Each hash
36
+ # has a :module_obj key and a :condition_proc key. Usually this
37
+ # method is only used internally in #apply_extensions, but if you
35
38
  # want to zero out all previously registered extensions you can call:
36
39
  # SolrDocument.registered_extensions = nil
37
40
  def registered_extensions