blacklight 7.7.0 → 7.8.0

Sign up to get free protection for your applications and to get access to all the features.
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