blacklight 9.0.0.beta1 → 9.0.0.beta2

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 (203) hide show
  1. checksums.yaml +4 -4
  2. data/.github/matrix.json +47 -0
  3. data/.github/workflows/build.yml +16 -0
  4. data/.github/workflows/lint.yml +25 -0
  5. data/.github/workflows/main.yml +22 -0
  6. data/.github/workflows/release_7_x_scheduled.yml +39 -0
  7. data/.github/workflows/release_8_x_scheduled.yml +39 -0
  8. data/.github/workflows/test.yml +53 -0
  9. data/.rubocop.yml +70 -2
  10. data/.rubocop_todo.yml +43 -67
  11. data/.solr_wrapper.yml +2 -0
  12. data/VERSION +1 -1
  13. data/app/assets/builds/blacklight.css +19 -15
  14. data/app/assets/javascripts/blacklight/blacklight.esm.js +31 -69
  15. data/app/assets/javascripts/blacklight/blacklight.esm.js.map +1 -1
  16. data/app/assets/javascripts/blacklight/blacklight.js +31 -69
  17. data/app/assets/javascripts/blacklight/blacklight.js.map +1 -1
  18. data/app/assets/stylesheets/blacklight/_bootstrap_overrides.scss +4 -0
  19. data/app/assets/stylesheets/blacklight/_facets.scss +2 -2
  20. data/app/assets/stylesheets/blacklight/_header.scss +4 -0
  21. data/app/assets/stylesheets/blacklight/_modal.scss +9 -8
  22. data/app/assets/stylesheets/blacklight/_pagination.scss +1 -3
  23. data/app/assets/stylesheets/blacklight/_search_history.scss +0 -4
  24. data/app/assets/stylesheets/blacklight/blacklight_defaults.scss +3 -0
  25. data/app/components/blacklight/advanced_search_form_component.rb +2 -2
  26. data/app/components/blacklight/constraints_component.rb +2 -2
  27. data/app/components/blacklight/document/action_component.rb +1 -3
  28. data/app/components/blacklight/document/bookmark_component.rb +2 -2
  29. data/app/components/blacklight/document/more_like_this_component.rb +2 -2
  30. data/app/components/blacklight/document/page_header_component.rb +2 -2
  31. data/app/components/blacklight/document/thumbnail_component.html.erb +3 -7
  32. data/app/components/blacklight/document/thumbnail_component.rb +7 -6
  33. data/app/components/blacklight/document_component.rb +3 -3
  34. data/app/components/blacklight/document_title_component.rb +3 -10
  35. data/app/components/blacklight/facet_field_checkboxes_component.rb +2 -20
  36. data/app/components/blacklight/facet_field_component.rb +2 -17
  37. data/app/components/blacklight/facet_field_filter_component.rb +2 -21
  38. data/app/components/blacklight/facet_field_inclusive_constraint_component.rb +4 -25
  39. data/app/components/blacklight/facet_field_list_component.rb +2 -32
  40. data/app/components/blacklight/facet_field_no_layout_component.rb +2 -10
  41. data/app/components/blacklight/facet_field_pagination_component.html.erb +2 -2
  42. data/app/components/blacklight/facet_item_component.rb +2 -74
  43. data/app/components/blacklight/facet_item_pivot_component.rb +1 -1
  44. data/app/components/blacklight/facets/checkboxes_component.rb +26 -0
  45. data/app/components/blacklight/facets/count_component.rb +23 -0
  46. data/app/components/blacklight/{facet_field_component.html.erb → facets/field_component.html.erb} +1 -1
  47. data/app/components/blacklight/facets/field_component.rb +23 -0
  48. data/app/components/blacklight/facets/filters_component.html.erb +4 -0
  49. data/app/components/blacklight/facets/filters_component.rb +27 -0
  50. data/app/components/blacklight/{facet_field_inclusive_constraint_component.html.erb → facets/inclusive_constraint_component.html.erb} +1 -1
  51. data/app/components/blacklight/facets/inclusive_constraint_component.rb +31 -0
  52. data/app/components/blacklight/{facet_field_filter_component.html.erb → facets/index_navigation_component.html.erb} +1 -1
  53. data/app/components/blacklight/facets/index_navigation_component.rb +32 -0
  54. data/app/components/blacklight/facets/item_component.rb +73 -0
  55. data/app/components/blacklight/facets/list_component.html.erb +11 -0
  56. data/app/components/blacklight/facets/list_component.rb +38 -0
  57. data/app/components/blacklight/facets/no_layout_component.rb +16 -0
  58. data/app/components/blacklight/facets/selected_value_component.rb +29 -0
  59. data/app/components/blacklight/facets/suggest_component.html.erb +12 -0
  60. data/app/components/blacklight/facets/suggest_component.rb +22 -0
  61. data/app/components/blacklight/metadata_field_plain_text_layout_component.rb +2 -2
  62. data/app/components/blacklight/response/facet_group_component.html.erb +1 -1
  63. data/app/components/blacklight/response/facet_group_component.rb +5 -1
  64. data/app/components/blacklight/system/dropdown_component.html.erb +1 -1
  65. data/app/components/blacklight/system/dropdown_component.rb +1 -1
  66. data/app/components/blacklight/top_navbar_component.html.erb +1 -1
  67. data/app/controllers/concerns/blacklight/bookmarks.rb +3 -3
  68. data/app/controllers/concerns/blacklight/catalog.rb +10 -25
  69. data/app/controllers/concerns/blacklight/controller.rb +1 -1
  70. data/app/controllers/concerns/blacklight/facetable.rb +34 -0
  71. data/app/controllers/concerns/blacklight/search_context.rb +1 -1
  72. data/app/controllers/concerns/blacklight/searchable.rb +1 -1
  73. data/app/helpers/blacklight/configuration_helper_behavior.rb +2 -2
  74. data/app/helpers/blacklight/document_helper_behavior.rb +3 -1
  75. data/app/helpers/blacklight/facets_helper_behavior.rb +9 -0
  76. data/app/helpers/blacklight/icon_helper_behavior.rb +2 -2
  77. data/app/javascript/blacklight-frontend/checkbox_submit.js +3 -0
  78. data/app/javascript/blacklight-frontend/debounce.js +1 -1
  79. data/app/javascript/blacklight-frontend/facet_suggest.js +23 -3
  80. data/app/javascript/blacklight-frontend/index.js +0 -2
  81. data/app/javascript/blacklight-frontend/modal.js +1 -4
  82. data/app/javascript/blacklight-frontend/search_context.js +3 -2
  83. data/app/models/facet_search_builder.rb +5 -0
  84. data/app/presenters/blacklight/facet_field_presenter.rb +1 -1
  85. data/app/presenters/blacklight/json_presenter.rb +1 -3
  86. data/app/presenters/blacklight/rendering/helper_method.rb +4 -4
  87. data/app/presenters/blacklight/rendering/join.rb +2 -2
  88. data/app/services/blacklight/facet_search_service.rb +44 -0
  89. data/app/services/blacklight/field_retriever.rb +1 -1
  90. data/app/services/blacklight/search_service.rb +6 -6
  91. data/app/values/blacklight/types.rb +2 -2
  92. data/app/views/catalog/_facet_pivot.html.erb +1 -1
  93. data/app/views/catalog/_home_text.html.erb +2 -2
  94. data/app/views/catalog/_sort_and_per_page.html.erb +1 -1
  95. data/app/views/catalog/facet.html.erb +8 -10
  96. data/config/locales/blacklight.ar.yml +2 -2
  97. data/config/locales/blacklight.es.yml +2 -2
  98. data/config/locales/blacklight.fr.yml +2 -2
  99. data/config/locales/blacklight.hu.yml +2 -2
  100. data/config/locales/blacklight.it.yml +2 -2
  101. data/config/locales/blacklight.nl.yml +1 -1
  102. data/config/locales/blacklight.pt-BR.yml +2 -2
  103. data/config/locales/blacklight.sq.yml +2 -2
  104. data/config/locales/blacklight.zh.yml +2 -2
  105. data/lib/blacklight/abstract_repository.rb +2 -2
  106. data/lib/blacklight/abstract_search_builder.rb +154 -0
  107. data/lib/blacklight/configuration/context.rb +3 -3
  108. data/lib/blacklight/configuration/facet_field.rb +6 -6
  109. data/lib/blacklight/configuration/field.rb +4 -4
  110. data/lib/blacklight/configuration/fields.rb +0 -1
  111. data/lib/blacklight/configuration/search_field.rb +1 -1
  112. data/lib/blacklight/configuration/view_config.rb +2 -2
  113. data/lib/blacklight/configuration.rb +6 -7
  114. data/lib/blacklight/facet_search_builder.rb +18 -0
  115. data/lib/blacklight/nested_open_struct_with_hash_access.rb +1 -1
  116. data/lib/blacklight/open_struct_with_hash_access.rb +2 -2
  117. data/lib/blacklight/search_builder.rb +1 -159
  118. data/lib/blacklight/search_state/filter_field.rb +4 -4
  119. data/lib/blacklight/search_state/pivot_filter_field.rb +4 -4
  120. data/lib/blacklight/solr/abstract_filter_query_builder.rb +77 -0
  121. data/lib/blacklight/solr/default_filter_query_builder.rb +20 -0
  122. data/lib/blacklight/solr/facet_search_builder_behavior.rb +62 -0
  123. data/lib/blacklight/solr/repository.rb +8 -9
  124. data/lib/blacklight/solr/response/facets.rb +2 -2
  125. data/lib/blacklight/solr/response/params.rb +0 -4
  126. data/lib/blacklight/solr/response.rb +5 -1
  127. data/lib/blacklight/solr/search_builder_behavior.rb +17 -132
  128. data/lib/blacklight.rb +1 -1
  129. data/lib/generators/blacklight/assets/importmap_generator.rb +3 -5
  130. data/lib/generators/blacklight/assets_generator.rb +1 -1
  131. data/lib/generators/blacklight/search_builder_generator.rb +1 -1
  132. data/lib/generators/blacklight/templates/.solr_wrapper.yml +2 -0
  133. data/lib/generators/blacklight/templates/catalog_controller.rb +3 -1
  134. data/lib/generators/blacklight/templates/solr/conf/solrconfig.xml +0 -4
  135. data/package.json +3 -3
  136. data/spec/components/blacklight/advanced_search_form_component_spec.rb +18 -22
  137. data/spec/components/blacklight/constraint_layout_component_spec.rb +8 -8
  138. data/spec/components/blacklight/constraints_component_spec.rb +11 -11
  139. data/spec/components/blacklight/document/action_component_spec.rb +23 -15
  140. data/spec/components/blacklight/document/group_component_spec.rb +10 -15
  141. data/spec/components/blacklight/document/page_header_component_spec.rb +35 -28
  142. data/spec/components/blacklight/document/sidebar_component_spec.rb +5 -11
  143. data/spec/components/blacklight/document_component_spec.rb +98 -65
  144. data/spec/components/blacklight/facet_component_spec.rb +12 -8
  145. data/spec/components/blacklight/facet_item_pivot_component_spec.rb +12 -12
  146. data/spec/components/blacklight/{facet_field_checkboxes_component_spec.rb → facets/checkboxes_component_spec.rb} +13 -13
  147. data/spec/components/blacklight/facets/filters_component_spec.rb +36 -0
  148. data/spec/components/blacklight/facets/index_navigation_component_spec.rb +40 -0
  149. data/spec/components/blacklight/{facet_item_component_spec.rb → facets/item_component_spec.rb} +10 -10
  150. data/spec/components/blacklight/{facet_field_list_component_spec.rb → facets/list_component_spec.rb} +23 -23
  151. data/spec/components/blacklight/facets/suggest_component_spec.rb +68 -0
  152. data/spec/components/blacklight/header_component_spec.rb +2 -4
  153. data/spec/components/blacklight/hidden_search_state_component_spec.rb +7 -7
  154. data/spec/components/blacklight/metadata_field_component_spec.rb +17 -15
  155. data/spec/components/blacklight/response/facet_group_component_spec.rb +37 -0
  156. data/spec/components/blacklight/response/pagination_component_spec.rb +1 -1
  157. data/spec/components/blacklight/response/spellcheck_component_spec.rb +1 -1
  158. data/spec/components/blacklight/search_bar_component_spec.rb +4 -4
  159. data/spec/components/blacklight/search_context/server_applied_params_component_spec.rb +2 -2
  160. data/spec/components/blacklight/search_context/server_item_pagination_component_spec.rb +3 -5
  161. data/spec/components/blacklight/skip_link_component_spec.rb +8 -11
  162. data/spec/components/blacklight/start_over_button_component_spec.rb +4 -4
  163. data/spec/components/blacklight/system/dropdown_component_spec.rb +26 -0
  164. data/spec/components/blacklight/system/flash_message_component_spec.rb +7 -11
  165. data/spec/controllers/catalog_controller_spec.rb +12 -20
  166. data/spec/features/facets_spec.rb +70 -7
  167. data/spec/helpers/blacklight/facets_helper_behavior_spec.rb +10 -0
  168. data/spec/lib/blacklight/configuration/facet_field_spec.rb +2 -2
  169. data/spec/lib/blacklight/parameters_spec.rb +12 -1
  170. data/spec/lib/blacklight/search_state/filter_field_spec.rb +18 -0
  171. data/spec/models/blacklight/configuration_spec.rb +32 -28
  172. data/spec/models/blacklight/facet_search_builder_spec.rb +19 -0
  173. data/spec/models/blacklight/search_builder_spec.rb +1 -11
  174. data/spec/models/blacklight/solr/default_filter_query_builder_spec.rb +72 -0
  175. data/spec/models/blacklight/solr/document_spec.rb +0 -4
  176. data/spec/models/blacklight/solr/facet_search_builder_behavior_spec.rb +929 -0
  177. data/spec/models/blacklight/solr/repository_spec.rb +31 -29
  178. data/spec/models/blacklight/solr/response/facets_spec.rb +86 -40
  179. data/spec/models/blacklight/solr/response/group_response_spec.rb +8 -5
  180. data/spec/models/blacklight/solr/response/group_spec.rb +9 -5
  181. data/spec/models/blacklight/solr/response_spec.rb +96 -64
  182. data/spec/models/blacklight/solr/search_builder_behavior_spec.rb +2 -227
  183. data/spec/models/solr_document_spec.rb +5 -1
  184. data/spec/services/blacklight/search_service_spec.rb +6 -27
  185. data/spec/spec_helper.rb +0 -1
  186. data/spec/support/view_component_test_helpers.rb +0 -18
  187. data/spec/views/catalog/facet.html.erb_spec.rb +10 -3
  188. data/spec/views/catalog/index.atom.builder_spec.rb +6 -3
  189. data/spec/views/catalog/index.html.erb_spec.rb +3 -1
  190. metadata +58 -29
  191. data/.github/workflows/ruby.yml +0 -98
  192. data/app/components/blacklight/facet_field_list_component.html.erb +0 -19
  193. data/app/components/blacklight/search/facet_suggest_input.html.erb +0 -9
  194. data/app/components/blacklight/search/facet_suggest_input.rb +0 -16
  195. data/app/javascript/blacklight-frontend/modalForm.js +0 -60
  196. data/app/views/catalog/_facet_index_navigation.html.erb +0 -1
  197. data/app/views/catalog/_facet_layout.html.erb +0 -8
  198. data/app/views/catalog/_facet_pagination.html.erb +0 -1
  199. data/spec/components/blacklight/document_metadata_component_spec.rb +0 -0
  200. data/spec/components/blacklight/search/facet_suggest_input_spec.rb +0 -33
  201. data/spec/views/catalog/_facet_index_navigation.html.erb_spec.rb +0 -43
  202. data/spec/views/catalog/_facet_layout.html.erb_spec.rb +0 -41
  203. /data/app/components/blacklight/{facet_field_checkboxes_component.html.erb → facets/checkboxes_component.html.erb} +0 -0
@@ -9,13 +9,13 @@ module Blacklight::Catalog
9
9
  include Blacklight::Configurable
10
10
  include Blacklight::SearchContext
11
11
  include Blacklight::Searchable
12
+ include Blacklight::Facetable
12
13
 
13
14
  # The following code is executed when someone includes blacklight::catalog in their
14
15
  # own controller.
15
16
  included do
16
17
  if respond_to? :helper_method
17
18
  helper_method :sms_mappings, :has_search_parameters?
18
- helper_method :search_facet_path
19
19
  end
20
20
 
21
21
  record_search_parameters
@@ -80,17 +80,19 @@ module Blacklight::Catalog
80
80
 
81
81
  # displays values and pagination links for a single facet field
82
82
  def facet
83
+ # @facet is a Blacklight::Configuration::FacetField
83
84
  @facet = blacklight_config.facet_fields[params[:id]]
84
85
  raise ActionController::RoutingError, 'Not Found' unless @facet
85
86
 
86
- query_fragment = params[:query_fragment] || ''
87
- @response = if query_fragment.present?
88
- search_service.facet_suggest_response(@facet.key, params[:query_fragment])
87
+ @response = if params[:query_fragment].present?
88
+ facet_search_service.facet_suggest_response(@facet.key, params[:query_fragment])
89
89
  else
90
- @response = search_service.facet_field_response(@facet.key)
90
+ facet_search_service.facet_field_response(@facet.key)
91
91
  end
92
+
92
93
  @display_facet = @response.aggregations[@facet.field]
93
94
 
95
+ # @presenter is a Blacklight::FacetFieldPresenter
94
96
  @presenter = @facet.presenter.new(@facet, @display_facet, view_context)
95
97
  @pagination = @presenter.paginator
96
98
  respond_to do |format|
@@ -139,15 +141,6 @@ module Blacklight::Catalog
139
141
  params[:search_field].present? || search_state.has_constraints?
140
142
  end
141
143
 
142
- def search_facet_path(options = {})
143
- opts = search_state
144
- .to_h
145
- .merge(action: "facet", only_path: true)
146
- .merge(options)
147
- .except(:page)
148
- url_for opts
149
- end
150
-
151
144
  private
152
145
 
153
146
  #
@@ -236,22 +229,14 @@ module Blacklight::Catalog
236
229
  # Email Action (this will render the appropriate view on GET requests and process the form and send the email on POST requests)
237
230
  def email_action documents
238
231
  mail = RecordMailer.email_record(documents, { to: params[:to], message: params[:message], config: blacklight_config }, url_options)
239
- if mail.respond_to? :deliver_now
240
- mail.deliver_now
241
- else
242
- mail.deliver
243
- end
232
+ mail.deliver_now
244
233
  end
245
234
 
246
235
  # SMS action (this will render the appropriate view on GET requests and process the form and send the email on POST requests)
247
236
  def sms_action documents
248
237
  to = "#{params[:to].gsub(/[^\d]/, '')}@#{params[:carrier]}"
249
238
  mail = RecordMailer.sms_record(documents, { to: to, config: blacklight_config }, url_options)
250
- if mail.respond_to? :deliver_now
251
- mail.deliver_now
252
- else
253
- mail.deliver
254
- end
239
+ mail.deliver_now
255
240
  end
256
241
 
257
242
  def validate_sms_params
@@ -293,7 +278,7 @@ module Blacklight::Catalog
293
278
  def blacklight_advanced_search_form_search_service
294
279
  form_search_state = search_state_class.new(blacklight_advanced_search_form_params, blacklight_config, self)
295
280
 
296
- search_service_class.new(config: blacklight_config, search_state: form_search_state, user_params: form_search_state.to_h, **search_service_context)
281
+ search_service_class.new(config: blacklight_config, search_state: form_search_state, **search_service_context)
297
282
  end
298
283
 
299
284
  def blacklight_advanced_search_form_params
@@ -130,7 +130,7 @@ module Blacklight::Controller
130
130
  # send the user home if the access was previously denied by the same
131
131
  # request to avoid sending the user back to the login page
132
132
  # (e.g. protected page -> logout -> returned to protected page -> home)
133
- redirect_to(root_url) && flash.discard && return if request.referer && request.referer.ends_with?(request.fullpath)
133
+ redirect_to(root_url) && flash.discard && return if request.referer&.ends_with?(request.fullpath)
134
134
 
135
135
  redirect_to(root_url) && return unless has_user_authentication_provider?
136
136
 
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ # The Facetable module can be included onto classes that need to initialize a FacetSearchService.
4
+ # There are two dependencies you must provide on the including class. Typically these
5
+ # would be provided by Blacklight::Controller
6
+ # 1. search_state
7
+ # 2. blacklight_config
8
+ #
9
+ # Additionally, the including class may override the facet_search_service_context method to provide
10
+ # further context to the SearchService. For example you could override this to provide the
11
+ # currently signed in user.
12
+ module Blacklight::Facetable
13
+ extend ActiveSupport::Concern
14
+
15
+ included do
16
+ # Which class to use for the search service. You can subclass SearchService if you
17
+ # want to override any of the methods (e.g. SearchService#fetch)
18
+ class_attribute :facet_search_service_class
19
+ self.facet_search_service_class = Blacklight::FacetSearchService
20
+ end
21
+
22
+ # @return [Blacklight::FacetSearchService]
23
+ def facet_search_service
24
+ facet_search_service_class.new(config: blacklight_config, search_state: search_state, user_params: search_state.to_h, **facet_search_service_context)
25
+ end
26
+
27
+ # Override this method on the class that includes Blacklight::Facetable to provide more context to the search service if necessary.
28
+ # For example, if your search builder needs to be aware of the current user, override this method to return a hash including the current user.
29
+ # Then the search builder could use some property about the current user to construct a constraint on the search.
30
+ # @return [Hash] a hash of context information to pass through to the search service
31
+ def facet_search_service_context
32
+ search_service_context
33
+ end
34
+ end
@@ -40,7 +40,7 @@ module Blacklight::SearchContext
40
40
  @page_link_data[:prev] = page_links_document_path(documents.first, index)
41
41
  @page_link_data[:next] = page_links_document_path(documents.last, index + 2)
42
42
  end
43
- if response&.total && response.total.positive?
43
+ if response&.total&.positive?
44
44
  @page_link_data[:counterRaw] = counter_param
45
45
  @page_link_data[:counterDelimited] = helpers.number_with_delimiter(counter_param.to_i)
46
46
  @page_link_data[:totalRaw] = response.total
@@ -21,7 +21,7 @@ module Blacklight::Searchable
21
21
 
22
22
  # @return [Blacklight::SearchService]
23
23
  def search_service
24
- search_service_class.new(config: blacklight_config, search_state: search_state, user_params: search_state.to_h, **search_service_context)
24
+ search_service_class.new(config: blacklight_config, search_state: search_state, **search_service_context)
25
25
  end
26
26
 
27
27
  # Override this method on the class that includes Blacklight::Searchable to provide more context to the search service if necessary.
@@ -96,7 +96,7 @@ module Blacklight::ConfigurationHelperBehavior
96
96
  #
97
97
  # @param [Blacklight::Solr::Configuration::Field] field_config
98
98
  # @return [Boolean]
99
- def should_render_field?(field_config, *args)
100
- blacklight_configuration_context.evaluate_if_unless_configuration field_config, *args
99
+ def should_render_field?(field_config, *)
100
+ blacklight_configuration_context.evaluate_if_unless_configuration(field_config, *)
101
101
  end
102
102
  end
@@ -38,10 +38,12 @@ module Blacklight::DocumentHelperBehavior
38
38
 
39
39
  ##
40
40
  # Check if the document is in the user's bookmarks
41
+ # Note: we do string comparison of the classes, because hot reloading in the development environment may cause each to have
42
+ # separate versions of the class loaded (see document.class.object_id and Bookmark#document_type.object_id)
41
43
  # @param [Blacklight::Document] document
42
44
  # @return [Boolean]
43
45
  def bookmarked? document
44
- current_bookmarks.any? { |x| x.document_id == document.id && x.document_type == document.class }
46
+ current_bookmarks.any? { |x| x.document_id == document.id && x.document_type.to_s == document.class.to_s }
45
47
  end
46
48
 
47
49
  ##
@@ -7,6 +7,15 @@ module Blacklight::FacetsHelperBehavior
7
7
  facet_config.presenter.new(facet_config, display_facet, self)
8
8
  end
9
9
 
10
+ def search_facet_path(options = {})
11
+ opts = search_state
12
+ .to_h
13
+ .merge(action: "facet", only_path: true)
14
+ .merge(options)
15
+ .except(:page)
16
+ url_for opts
17
+ end
18
+
10
19
  private
11
20
 
12
21
  def facet_value_for_facet_item item
@@ -7,7 +7,7 @@ module Blacklight::IconHelperBehavior
7
7
  # Returns the raw SVG (String) for a Blacklight Icon
8
8
  # @param [String, Symbol] icon_name
9
9
  # @return [String]
10
- def blacklight_icon(icon_name, **kwargs)
11
- render "Blacklight::Icons::#{icon_name.to_s.camelize}Component".constantize.new(**kwargs)
10
+ def blacklight_icon(icon_name, **)
11
+ render "Blacklight::Icons::#{icon_name.to_s.camelize}Component".constantize.new(**)
12
12
  end
13
13
  end
@@ -36,6 +36,9 @@ export default class CheckboxSubmit {
36
36
  }).then((json) => {
37
37
  this.labelTarget.removeAttribute('disabled')
38
38
  this.checkboxTarget.removeAttribute('disabled')
39
+ // For accessibility return keyboard focus
40
+ // back to the checkbox after form submission
41
+ this.checkboxTarget.focus()
39
42
  this.updateStateFor(!this.checked)
40
43
  this.bookmarksCounter().forEach(counter => {
41
44
  counter.innerHTML = json.bookmarks.count;
@@ -3,7 +3,7 @@
3
3
  // const basicFunction = (entry) => console.log(entry)
4
4
  // const debounced = debounce(basicFunction("I should only be called once"));
5
5
  //
6
- // debounced // does NOT print to the screen becase it is invoked again less than 200 milliseconds later
6
+ // debounced // does NOT print to the screen because it is invoked again less than 200 milliseconds later
7
7
  // debounced // does print to the screen
8
8
  // ```
9
9
  export default function debounce(func, timeout = 200) {
@@ -4,20 +4,40 @@ const FacetSuggest = async (e) => {
4
4
  if (e.target.matches('.facet-suggest')) {
5
5
  const queryFragment = e.target.value?.trim();
6
6
  const facetField = e.target.dataset.facetField;
7
+ const facetArea = document.querySelector('.facet-extended-list');
8
+ const prevNextLinks = document.querySelectorAll('.prev_next_links');
9
+
7
10
  if (!facetField) { return; }
8
11
 
9
- const urlToFetch = `/catalog/facet_suggest/${facetField}/${queryFragment}${window.location.search}`
12
+ // Get the search params from the current query so the facet suggestions
13
+ // can retain that context.
14
+ const facetSearchContext = e.target.dataset.facetSearchContext;
15
+ const url = new URL(facetSearchContext, window.location.origin);
16
+
17
+ // Drop facet.page so a filtered suggestion list will always start on page 1
18
+ url.searchParams.delete('facet.page');
19
+ const facetSearchParams = url.searchParams.toString();
20
+
21
+ const urlToFetch = `/catalog/facet_suggest/${facetField}/${queryFragment}?${facetSearchParams}`;
22
+
10
23
  const response = await fetch(urlToFetch);
11
24
  if (response.ok) {
12
25
  const blob = await response.blob()
13
26
  const text = await blob.text()
14
27
 
15
- const facetArea = document.querySelector('.facet-extended-list');
16
-
17
28
  if (text && facetArea) {
18
29
  facetArea.innerHTML = text
19
30
  }
20
31
  }
32
+
33
+ // Hide the prev/next links when a user enters text in the facet
34
+ // suggestion input. They don't work with a filtered list.
35
+ prevNextLinks.forEach(element => {
36
+ element.classList.toggle('invisible', !!queryFragment);
37
+ });
38
+
39
+ // Add a class to distinguish suggested facet values vs. regular.
40
+ facetArea.classList.toggle('facet-suggestions', !!queryFragment);
21
41
  }
22
42
  };
23
43
 
@@ -2,7 +2,6 @@ import BookmarkToggle from 'blacklight-frontend/bookmark_toggle'
2
2
  import ButtonFocus from 'blacklight-frontend/button_focus'
3
3
  import FacetSuggest from 'blacklight-frontend/facet_suggest'
4
4
  import Modal from 'blacklight-frontend/modal'
5
- import ModalForm from 'blacklight-frontend/modalForm'
6
5
  import SearchContext from 'blacklight-frontend/search_context'
7
6
  import Core from 'blacklight-frontend/core'
8
7
 
@@ -11,7 +10,6 @@ export default {
11
10
  ButtonFocus,
12
11
  FacetSuggest,
13
12
  Modal,
14
- ModalForm,
15
13
  SearchContext,
16
14
  Core,
17
15
  onLoad: Core.onLoad
@@ -56,9 +56,6 @@
56
56
  const Modal = (() => {
57
57
  const modal = {}
58
58
 
59
- // bootstrap class that will stop body scrolling when modal is open
60
- const bootstrapBodyClassOpen = "modal-open";
61
-
62
59
  // a Bootstrap modal div that should be already on the page hidden
63
60
  modal.modalSelector = '#blacklight-modal';
64
61
 
@@ -137,7 +134,7 @@ const Modal = (() => {
137
134
 
138
135
  modal.modalAjaxLinkClick = function(e) {
139
136
  e.preventDefault();
140
- const href = e.target.getAttribute('href')
137
+ const href = e.target.closest('a').getAttribute('href')
141
138
  fetch(href)
142
139
  .then(response => {
143
140
  if (!response.ok) {
@@ -1,6 +1,7 @@
1
1
  const SearchContext = (e) => {
2
- if (e.target.matches('[data-context-href]')) {
3
- SearchContext.handleSearchContextMethod.call(e.target, e)
2
+ const contextLink = e.target.closest('[data-context-href]')
3
+ if (contextLink) {
4
+ SearchContext.handleSearchContextMethod.call(contextLink, e)
4
5
  }
5
6
  }
6
7
 
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class FacetSearchBuilder < Blacklight::FacetSearchBuilder
4
+ include Blacklight::Solr::FacetSearchBuilderBehavior
5
+ end
@@ -4,7 +4,7 @@ module Blacklight
4
4
  class FacetFieldPresenter
5
5
  attr_reader :facet_field, :display_facet, :view_context, :search_state
6
6
 
7
- delegate :key, to: :facet_field
7
+ delegate :key, :suggest, to: :facet_field
8
8
  delegate :field_name, to: :display_facet
9
9
 
10
10
  def initialize(facet_field, display_facet, view_context, search_state = view_context.search_state)
@@ -13,9 +13,7 @@ module Blacklight
13
13
 
14
14
  delegate :facet_field_names, :facet_configuration_for_field, to: :blacklight_config
15
15
 
16
- def documents
17
- @response.documents
18
- end
16
+ delegate :documents, to: :@response
19
17
 
20
18
  # @return [Array<Blacklight::Solr::Response::Facets::FacetField>]
21
19
  def search_facets
@@ -15,10 +15,10 @@ module Blacklight
15
15
 
16
16
  def render_helper
17
17
  context.send(config.helper_method,
18
- **options.merge(document: document,
19
- field: config.field,
20
- config: config,
21
- value: values))
18
+ **options, document: document,
19
+ field: config.field,
20
+ config: config,
21
+ value: values)
22
22
  end
23
23
  end
24
24
  end
@@ -16,8 +16,8 @@ module Blacklight
16
16
 
17
17
  private
18
18
 
19
- def html_escape(*args)
20
- ERB::Util.html_escape(*args)
19
+ def html_escape(*)
20
+ ERB::Util.html_escape(*)
21
21
  end
22
22
  end
23
23
  end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ # FacetSearchService returns a facet list from the repository. This is for drawing the "more facets" modal
4
+ module Blacklight
5
+ class FacetSearchService
6
+ def initialize(config:, search_state:, search_builder_class: config.facet_search_builder_class, **context)
7
+ @blacklight_config = config
8
+ @search_state = search_state
9
+ @user_params = @search_state.params
10
+ @search_builder_class = search_builder_class
11
+ @context = context
12
+ end
13
+
14
+ # The blacklight_config + controller are accessed by the search_builder
15
+ attr_reader :blacklight_config, :context
16
+
17
+ def search_builder
18
+ search_builder_class.new(self)
19
+ end
20
+
21
+ def search_state_class
22
+ @search_state.class
23
+ end
24
+
25
+ ##
26
+ # Get the solr response when retrieving only a single facet field
27
+ # @return [Blacklight::Solr::Response] the solr response
28
+ def facet_field_response(facet_field, extra_controller_params = {})
29
+ query = search_builder.with(search_state).facet(facet_field)
30
+ repository.search(params: query.merge(extra_controller_params))
31
+ end
32
+
33
+ def facet_suggest_response(facet_field, facet_suggestion_query, extra_controller_params = {})
34
+ query = search_builder.with(search_state).facet(facet_field).facet_suggestion_query(facet_suggestion_query)
35
+ repository.search(params: query.merge(extra_controller_params))
36
+ end
37
+
38
+ private
39
+
40
+ attr_reader :search_builder_class, :search_state
41
+
42
+ delegate :repository, to: :blacklight_config
43
+ end
44
+ end
@@ -41,7 +41,7 @@ module Blacklight
41
41
 
42
42
  def retrieve_simple
43
43
  # regular document field
44
- if field_config.default && field_config.default.is_a?(Proc)
44
+ if field_config.default.is_a?(Proc)
45
45
  document.fetch(field_config.field, &field_config.default)
46
46
  else
47
47
  document.fetch(field_config.field, field_config.default)
@@ -3,9 +3,9 @@
3
3
  # SearchService returns search results from the repository
4
4
  module Blacklight
5
5
  class SearchService
6
- def initialize(config:, search_state: nil, user_params: nil, search_builder_class: config.search_builder_class, **context)
6
+ def initialize(config:, search_state:, search_builder_class: config.search_builder_class, **context)
7
7
  @blacklight_config = config
8
- @search_state = search_state || Blacklight::SearchState.new(user_params || {}, config)
8
+ @search_state = search_state
9
9
  @user_params = @search_state.params
10
10
  @search_builder_class = search_builder_class
11
11
  @context = context
@@ -31,7 +31,7 @@ module Blacklight
31
31
  builder.rows = search_state.per_page
32
32
 
33
33
  builder = yield(builder) if block_given?
34
- response = repository.search(builder)
34
+ response = repository.search(params: builder)
35
35
 
36
36
  if response.grouped? && grouped_key_for_results
37
37
  response.group(grouped_key_for_results)
@@ -59,12 +59,12 @@ module Blacklight
59
59
  # @return [Blacklight::Solr::Response] the solr response
60
60
  def facet_field_response(facet_field, extra_controller_params = {})
61
61
  query = search_builder.with(search_state).facet(facet_field)
62
- repository.search(query.merge(extra_controller_params))
62
+ repository.search(params: query.merge(extra_controller_params))
63
63
  end
64
64
 
65
65
  def facet_suggest_response(facet_field, facet_suggestion_query, extra_controller_params = {})
66
66
  query = search_builder.with(search_state).facet(facet_field).facet_suggestion_query(facet_suggestion_query)
67
- repository.search(query.merge(extra_controller_params))
67
+ repository.search(params: query.merge(extra_controller_params))
68
68
  end
69
69
 
70
70
  # Get the previous and next document from a search result
@@ -73,7 +73,7 @@ module Blacklight
73
73
  p = previous_and_next_document_params(index)
74
74
  new_state = request_params.is_a?(Blacklight::SearchState) ? request_params : Blacklight::SearchState.new(request_params, blacklight_config)
75
75
  query = search_builder.with(new_state).start(p.delete(:start)).rows(p.delete(:rows)).merge(extra_controller_params).merge(p)
76
- response = repository.search(query)
76
+ response = repository.search(params: query)
77
77
  document_list = response.documents
78
78
 
79
79
  # only get the previous doc if there is one
@@ -95,8 +95,8 @@ module Blacklight
95
95
  end
96
96
 
97
97
  class Selector < Array
98
- def initialize(by: nil, block: nil, **kwargs)
99
- super(**kwargs)
98
+ def initialize(by: nil, block: nil, **)
99
+ super(**)
100
100
  @by = by
101
101
  @block = block
102
102
  end
@@ -1,3 +1,3 @@
1
- <%= render(Blacklight::FacetFieldListComponent.new(
1
+ <%= render(Blacklight::Facets::ListComponent.new(
2
2
  facet_field: facet_field_presenter(facet_field.merge(item_component: Blacklight::FacetItemPivotComponent), display_facet),
3
3
  layout: false)) %>
@@ -1,5 +1,5 @@
1
- <div class="jumbotron text-center p-5 mb-4 bg-light rounded-3">
2
- <h1 class="jumbotron-heading"><%= t('blacklight.welcome') %></h1>
1
+ <div class="text-center p-5 mb-4 bg-light rounded-3">
2
+ <h1 class="fw-bold"><%= t('blacklight.welcome') %></h1>
3
3
 
4
4
  <p class="lead">Blacklight is a multi-institutional open-source collaboration building a better discovery platform framework.</p>
5
5
 
@@ -1,4 +1,4 @@
1
- <div id="sortAndPerPage" class="sort-pagination pb-3 d-md-flex justify-content-between" role="navigation" aria-label="<%= t('blacklight.search.per_page.aria_label')%>">
1
+ <div id="sortAndPerPage" class="sort-pagination pb-3 mb-3 d-md-flex justify-content-between" role="navigation" aria-label="<%= t('blacklight.search.per_page.aria_label')%>">
2
2
  <%= render partial: "paginate_compact", object: @response if show_pagination? %>
3
3
  <%= render_results_collection_tools wrapping_class: "search-widgets" %>
4
4
  </div>
@@ -1,14 +1,12 @@
1
1
  <%= render Blacklight::System::ModalComponent.new do |component| %>
2
- <% component.with_prefix do %>
3
- <div class="facet-pagination top d-flex w-100 justify-content-between">
4
- <%= render :partial=>'facet_pagination' %>
5
- </div>
6
- <% end %>
7
-
8
2
  <% component.with_title { facet_field_label(@facet.key) } %>
9
- <%= render Blacklight::Search::FacetSuggestInput.new(facet: @facet, presenter: @presenter) %>
3
+ <% view_config = blacklight_config.view_config(document_index_view_type) %>
10
4
 
11
- <%= render partial: 'facet_index_navigation' if @facet.index_range && @display_facet.index? %>
5
+ <%= render Blacklight::Facets::FiltersComponent.new(presenter: @presenter) %>
6
+
7
+ <div class="facet-pagination top d-flex flex-wrap w-100 justify-content-between border-bottom pb-3 mb-3">
8
+ <%= render view_config.facet_pagination_component.new(facet_field: @presenter) %>
9
+ </div>
12
10
 
13
11
  <div class="facet-extended-list">
14
12
  <%= render Blacklight::FacetComponent.new(display_facet: @display_facet,
@@ -17,8 +15,8 @@
17
15
  </div>
18
16
 
19
17
  <% component.with_footer do %>
20
- <div class="facet-pagination bottom flex-row justify-content-between">
21
- <%= render :partial=>'facet_pagination' %>
18
+ <div class="facet-pagination bottom d-flex flex-wrap w-100 justify-content-between">
19
+ <%= render view_config.facet_pagination_component.new(facet_field: @presenter) %>
22
20
  </div>
23
21
  <% end %>
24
22
  <% end %>
@@ -112,8 +112,8 @@ ar:
112
112
  count: ترتيب رقمي
113
113
  index: ترتيب أبجدي
114
114
  suggest:
115
- label: Filter %{field_label}
116
- placeholder: Filter...
115
+ label: الفلتر %{field_label}
116
+ placeholder: فلتر...
117
117
  title: تحديد نطاق البحث
118
118
  filters:
119
119
  label: "%{label}:"
@@ -102,8 +102,8 @@ es:
102
102
  count: Ordenación numérica
103
103
  index: Ordenación A-Z
104
104
  suggest:
105
- label: Filter %{field_label}
106
- placeholder: Filter...
105
+ label: Filtro %{field_label}
106
+ placeholder: Filtrar...
107
107
  title: Limite su búsqueda
108
108
  filters:
109
109
  label: "%{label}:"
@@ -102,8 +102,8 @@ fr:
102
102
  count: Du + au - fréquent
103
103
  index: Tri de A à Z
104
104
  suggest:
105
- label: Filter %{field_label}
106
- placeholder: Filter...
105
+ label: Filtre %{field_label}
106
+ placeholder: Filtre...
107
107
  title: Limiter votre recherche
108
108
  filters:
109
109
  label: "%{label}:"
@@ -100,8 +100,8 @@ hu:
100
100
  count: Numerikus rendezés
101
101
  index: A-Z rendezés
102
102
  suggest:
103
- label: Filter %{field_label}
104
- placeholder: Filter...
103
+ label: Szűrő %{field_label}
104
+ placeholder: Szűrő...
105
105
  title: Szűrje tovább a keresését
106
106
  filters:
107
107
  label: "%{label}:"
@@ -103,8 +103,8 @@ it:
103
103
  count: Ordina per numero
104
104
  index: Ordina A-Z
105
105
  suggest:
106
- label: Filter %{field_label}
107
- placeholder: Filter...
106
+ label: Filtro %{field_label}
107
+ placeholder: Filtro...
108
108
  title: Affina la ricerca
109
109
  filters:
110
110
  label: "%{label}:"
@@ -100,7 +100,7 @@ nl:
100
100
  count: Numeriek sorteren
101
101
  index: A-Z Sorteren
102
102
  suggest:
103
- label: Filter %{field_label}
103
+ label: Filteren %{field_label}
104
104
  placeholder: Filter...
105
105
  title: Verfijn uw zoekopdracht
106
106
  filters:
@@ -101,8 +101,8 @@ pt-BR:
101
101
  count: Ordenar por Número
102
102
  index: Ordem Alfabética A-Z
103
103
  suggest:
104
- label: Filter %{field_label}
105
- placeholder: Filter...
104
+ label: Filtro %{field_label}
105
+ placeholder: Filtro...
106
106
  title: Filtre sua busca
107
107
  filters:
108
108
  label: "%{label}:"
@@ -100,8 +100,8 @@ sq:
100
100
  count: Renditja numerike
101
101
  index: A-Z Renditja
102
102
  suggest:
103
- label: Filter %{field_label}
104
- placeholder: Filter...
103
+ label: Filtri %{field_label}
104
+ placeholder: Filtro...
105
105
  title: Kufizo këkimin
106
106
  filters:
107
107
  label: "%{label}:"