blacklight 9.0.0.beta1 → 9.0.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 (263) hide show
  1. checksums.yaml +4 -4
  2. data/.docker/app/Dockerfile +2 -1
  3. data/.github/matrix.json +55 -0
  4. data/.github/workflows/build.yml +16 -0
  5. data/.github/workflows/lint.yml +25 -0
  6. data/.github/workflows/main.yml +22 -0
  7. data/.github/workflows/release_7_x_scheduled.yml +39 -0
  8. data/.github/workflows/release_8_x_scheduled.yml +39 -0
  9. data/.github/workflows/test.yml +53 -0
  10. data/.rubocop.yml +81 -3
  11. data/.rubocop_todo.yml +46 -71
  12. data/.solr_wrapper.yml +3 -1
  13. data/README.md +2 -2
  14. data/VERSION +1 -1
  15. data/app/assets/builds/blacklight.css +51 -38
  16. data/app/assets/javascripts/blacklight/blacklight.esm.js +62 -77
  17. data/app/assets/javascripts/blacklight/blacklight.esm.js.map +1 -1
  18. data/app/assets/javascripts/blacklight/blacklight.js +62 -77
  19. data/app/assets/javascripts/blacklight/blacklight.js.map +1 -1
  20. data/app/assets/stylesheets/blacklight/_blacklight_base.scss +0 -1
  21. data/app/assets/stylesheets/blacklight/_bootstrap_overrides.scss +4 -0
  22. data/app/assets/stylesheets/blacklight/_facets.scss +37 -29
  23. data/app/assets/stylesheets/blacklight/_header.scss +4 -0
  24. data/app/assets/stylesheets/blacklight/_modal.scss +9 -8
  25. data/app/assets/stylesheets/blacklight/_pagination.scss +1 -3
  26. data/app/assets/stylesheets/blacklight/_search_history.scss +0 -4
  27. data/app/assets/stylesheets/blacklight/blacklight_defaults.scss +3 -0
  28. data/app/components/blacklight/advanced_search_form_component.html.erb +4 -4
  29. data/app/components/blacklight/advanced_search_form_component.rb +6 -5
  30. data/app/components/blacklight/constraint_component.html.erb +1 -5
  31. data/app/components/blacklight/constraint_component.rb +11 -0
  32. data/app/components/blacklight/constraint_layout_component.html.erb +1 -6
  33. data/app/components/blacklight/constraint_layout_component.rb +9 -0
  34. data/app/components/blacklight/constraints_component.html.erb +3 -8
  35. data/app/components/blacklight/constraints_component.rb +59 -14
  36. data/app/components/blacklight/document/action_component.rb +1 -3
  37. data/app/components/blacklight/document/bookmark_component.html.erb +3 -3
  38. data/app/components/blacklight/document/bookmark_component.rb +10 -4
  39. data/app/components/blacklight/document/group_component.html.erb +1 -1
  40. data/app/components/blacklight/document/more_like_this_component.rb +2 -2
  41. data/app/components/blacklight/document/page_header_component.rb +3 -3
  42. data/app/components/blacklight/document/thumbnail_component.html.erb +3 -7
  43. data/app/components/blacklight/document/thumbnail_component.rb +7 -6
  44. data/app/components/blacklight/document_component.html.erb +3 -3
  45. data/app/components/blacklight/document_component.rb +22 -26
  46. data/app/components/blacklight/document_title_component.rb +6 -10
  47. data/app/components/blacklight/facet_field_checkboxes_component.rb +4 -18
  48. data/app/components/blacklight/facet_field_component.rb +4 -15
  49. data/app/components/blacklight/facet_field_filter_component.rb +4 -19
  50. data/app/components/blacklight/facet_field_inclusive_constraint_component.rb +4 -23
  51. data/app/components/blacklight/facet_field_list_component.rb +4 -30
  52. data/app/components/blacklight/facet_field_no_layout_component.rb +4 -8
  53. data/app/components/blacklight/facet_field_pagination_component.html.erb +2 -2
  54. data/app/components/blacklight/facet_item_component.rb +4 -72
  55. data/app/components/blacklight/facet_item_pivot_component.rb +8 -4
  56. data/app/components/blacklight/{facet_field_checkboxes_component.html.erb → facets/checkboxes_component.html.erb} +4 -4
  57. data/app/components/blacklight/facets/checkboxes_component.rb +26 -0
  58. data/app/components/blacklight/facets/count_component.rb +23 -0
  59. data/app/components/blacklight/{facet_field_component.html.erb → facets/field_component.html.erb} +1 -3
  60. data/app/components/blacklight/facets/field_component.rb +23 -0
  61. data/app/components/blacklight/facets/filters_component.html.erb +4 -0
  62. data/app/components/blacklight/facets/filters_component.rb +39 -0
  63. data/app/components/blacklight/{facet_field_inclusive_constraint_component.html.erb → facets/inclusive_constraint_component.html.erb} +1 -1
  64. data/app/components/blacklight/facets/inclusive_constraint_component.rb +31 -0
  65. data/app/components/blacklight/{facet_field_filter_component.html.erb → facets/index_navigation_component.html.erb} +1 -1
  66. data/app/components/blacklight/facets/index_navigation_component.rb +32 -0
  67. data/app/components/blacklight/facets/item_component.rb +76 -0
  68. data/app/components/blacklight/facets/list_component.html.erb +11 -0
  69. data/app/components/blacklight/facets/list_component.rb +46 -0
  70. data/app/components/blacklight/facets/no_layout_component.rb +16 -0
  71. data/app/components/blacklight/facets/pivot_list_component.rb +14 -0
  72. data/app/components/blacklight/facets/selected_value_component.rb +29 -0
  73. data/app/components/blacklight/facets/suggest_component.html.erb +17 -0
  74. data/app/components/blacklight/facets/suggest_component.rb +21 -0
  75. data/app/components/blacklight/header_component.rb +2 -2
  76. data/app/components/blacklight/icons/remove_component.rb +2 -2
  77. data/app/components/blacklight/metadata_field_component.html.erb +2 -2
  78. data/app/components/blacklight/metadata_field_component.rb +2 -1
  79. data/app/components/blacklight/metadata_field_layout_component.rb +9 -4
  80. data/app/components/blacklight/metadata_field_plain_text_layout_component.rb +2 -2
  81. data/app/components/blacklight/response/facet_group_component.html.erb +3 -3
  82. data/app/components/blacklight/response/facet_group_component.rb +9 -1
  83. data/app/components/blacklight/search_bar_component.html.erb +2 -2
  84. data/app/components/blacklight/system/dropdown_component.html.erb +1 -1
  85. data/app/components/blacklight/system/dropdown_component.rb +1 -1
  86. data/app/components/blacklight/system/flash_message_component.html.erb +1 -1
  87. data/app/components/blacklight/system/flash_message_component.rb +0 -9
  88. data/app/components/blacklight/system/modal_component.html.erb +1 -2
  89. data/app/components/blacklight/top_navbar_component.html.erb +2 -2
  90. data/app/controllers/concerns/blacklight/bookmarks.rb +13 -3
  91. data/app/controllers/concerns/blacklight/catalog.rb +27 -30
  92. data/app/controllers/concerns/blacklight/controller.rb +1 -1
  93. data/app/controllers/concerns/blacklight/search_context.rb +1 -1
  94. data/app/controllers/concerns/blacklight/searchable.rb +1 -1
  95. data/app/helpers/blacklight/catalog_helper_behavior.rb +5 -3
  96. data/app/helpers/blacklight/configuration_helper_behavior.rb +2 -2
  97. data/app/helpers/blacklight/document_helper_behavior.rb +3 -1
  98. data/app/helpers/blacklight/facets_helper_behavior.rb +7 -12
  99. data/app/helpers/blacklight/icon_helper_behavior.rb +2 -2
  100. data/app/javascript/blacklight-frontend/bookmark_toggle.js +7 -2
  101. data/app/javascript/blacklight-frontend/button_focus.js +1 -1
  102. data/app/javascript/blacklight-frontend/checkbox_submit.js +9 -2
  103. data/app/javascript/blacklight-frontend/debounce.js +1 -1
  104. data/app/javascript/blacklight-frontend/facet_suggest.js +27 -3
  105. data/app/javascript/blacklight-frontend/index.js +0 -2
  106. data/app/javascript/blacklight-frontend/modal.js +15 -8
  107. data/app/javascript/blacklight-frontend/search_context.js +3 -2
  108. data/app/presenters/blacklight/constraint_presenter.rb +22 -0
  109. data/app/presenters/blacklight/document_presenter.rb +6 -5
  110. data/app/presenters/blacklight/facet_field_presenter.rb +18 -2
  111. data/app/presenters/blacklight/facet_grouped_item_presenter.rb +6 -0
  112. data/app/presenters/blacklight/facet_item_pivot_presenter.rb +1 -5
  113. data/app/presenters/blacklight/facet_item_presenter.rb +5 -18
  114. data/app/presenters/blacklight/field_presenter.rb +4 -2
  115. data/app/presenters/blacklight/json_presenter.rb +8 -4
  116. data/app/presenters/blacklight/rendering/abstract_step.rb +7 -1
  117. data/app/presenters/blacklight/rendering/helper_method.rb +4 -4
  118. data/app/presenters/blacklight/rendering/join.rb +11 -7
  119. data/app/presenters/blacklight/rendering/terminator.rb +1 -1
  120. data/app/services/blacklight/field_retriever.rb +1 -1
  121. data/app/services/blacklight/search_service.rb +10 -8
  122. data/app/values/blacklight/types.rb +2 -2
  123. data/app/views/blacklight/nav/_bookmark.html.erb +1 -1
  124. data/app/views/catalog/_document.atom.builder +1 -1
  125. data/app/views/catalog/_document.html.erb +1 -1
  126. data/app/views/catalog/_email_form.html.erb +4 -4
  127. data/app/views/catalog/_home_text.html.erb +2 -2
  128. data/app/views/catalog/_show_main_content.html.erb +9 -5
  129. data/app/views/catalog/_sms_form.html.erb +4 -4
  130. data/app/views/catalog/_sort_and_per_page.html.erb +1 -1
  131. data/app/views/catalog/advanced_search.html.erb +1 -1
  132. data/app/views/catalog/facet.html.erb +8 -10
  133. data/app/views/catalog/index.html.erb +0 -1
  134. data/app/views/catalog/index.json.jbuilder +5 -3
  135. data/app/views/catalog/show.html.erb +2 -2
  136. data/app/views/layouts/blacklight/base.html.erb +1 -1
  137. data/blacklight.gemspec +1 -1
  138. data/config/locales/blacklight.ar.yml +14 -14
  139. data/config/locales/blacklight.ca.yml +2 -2
  140. data/config/locales/blacklight.de.yml +13 -13
  141. data/config/locales/blacklight.en.yml +3 -3
  142. data/config/locales/blacklight.es.yml +13 -13
  143. data/config/locales/blacklight.fr.yml +14 -14
  144. data/config/locales/blacklight.hu.yml +15 -15
  145. data/config/locales/blacklight.it.yml +16 -16
  146. data/config/locales/blacklight.nl.yml +13 -13
  147. data/config/locales/blacklight.pt-BR.yml +15 -15
  148. data/config/locales/blacklight.sq.yml +14 -14
  149. data/config/locales/blacklight.zh.yml +12 -12
  150. data/lib/blacklight/abstract_repository.rb +2 -2
  151. data/lib/blacklight/component.rb +7 -1
  152. data/lib/blacklight/configuration/context.rb +3 -3
  153. data/lib/blacklight/configuration/facet_field.rb +11 -6
  154. data/lib/blacklight/configuration/field.rb +4 -4
  155. data/lib/blacklight/configuration/fields.rb +0 -1
  156. data/lib/blacklight/configuration/search_field.rb +1 -1
  157. data/lib/blacklight/configuration/view_config.rb +32 -18
  158. data/lib/blacklight/configuration.rb +64 -10
  159. data/lib/blacklight/nested_open_struct_with_hash_access.rb +1 -1
  160. data/lib/blacklight/open_struct_with_hash_access.rb +2 -2
  161. data/lib/blacklight/routes/searchable.rb +1 -1
  162. data/lib/blacklight/search_builder.rb +2 -1
  163. data/lib/blacklight/search_state/filter_field.rb +4 -4
  164. data/lib/blacklight/search_state/pivot_filter_field.rb +5 -5
  165. data/lib/blacklight/search_state.rb +2 -0
  166. data/lib/blacklight/solr/abstract_filter_query_builder.rb +77 -0
  167. data/lib/blacklight/solr/default_filter_query_builder.rb +20 -0
  168. data/lib/blacklight/solr/field_reflection_search_builder.rb +11 -0
  169. data/lib/blacklight/solr/repository.rb +17 -15
  170. data/lib/blacklight/solr/response/facets.rb +2 -2
  171. data/lib/blacklight/solr/response/params.rb +0 -4
  172. data/lib/blacklight/solr/response.rb +5 -1
  173. data/lib/blacklight/solr/search_builder_behavior.rb +48 -97
  174. data/lib/blacklight/solr/single_doc_search_builder.rb +25 -0
  175. data/lib/blacklight.rb +6 -4
  176. data/lib/generators/blacklight/assets/importmap_generator.rb +3 -5
  177. data/lib/generators/blacklight/assets_generator.rb +1 -1
  178. data/lib/generators/blacklight/search_builder_generator.rb +1 -1
  179. data/lib/generators/blacklight/templates/.solr_wrapper.yml +3 -1
  180. data/lib/generators/blacklight/templates/catalog_controller.rb +34 -8
  181. data/lib/generators/blacklight/templates/solr/conf/solrconfig.xml +0 -71
  182. data/package.json +3 -3
  183. data/spec/components/blacklight/advanced_search_form_component_spec.rb +18 -22
  184. data/spec/components/blacklight/constraint_layout_component_spec.rb +8 -8
  185. data/spec/components/blacklight/constraints_component_spec.rb +11 -11
  186. data/spec/components/blacklight/document/action_component_spec.rb +23 -15
  187. data/spec/components/blacklight/document/group_component_spec.rb +10 -15
  188. data/spec/components/blacklight/document/page_header_component_spec.rb +35 -28
  189. data/spec/components/blacklight/document/sidebar_component_spec.rb +5 -11
  190. data/spec/components/blacklight/document_component_spec.rb +105 -79
  191. data/spec/components/blacklight/facet_component_spec.rb +12 -8
  192. data/spec/components/blacklight/facet_item_pivot_component_spec.rb +12 -12
  193. data/spec/components/blacklight/{facet_field_checkboxes_component_spec.rb → facets/checkboxes_component_spec.rb} +13 -13
  194. data/spec/components/blacklight/facets/filters_component_spec.rb +36 -0
  195. data/spec/components/blacklight/facets/index_navigation_component_spec.rb +41 -0
  196. data/spec/components/blacklight/{facet_item_component_spec.rb → facets/item_component_spec.rb} +10 -10
  197. data/spec/components/blacklight/{facet_field_list_component_spec.rb → facets/list_component_spec.rb} +34 -23
  198. data/spec/components/blacklight/facets/pivot_list_component_spec.rb +53 -0
  199. data/spec/components/blacklight/facets/suggest_component_spec.rb +82 -0
  200. data/spec/components/blacklight/header_component_spec.rb +2 -4
  201. data/spec/components/blacklight/hidden_search_state_component_spec.rb +7 -7
  202. data/spec/components/blacklight/metadata_field_component_spec.rb +17 -15
  203. data/spec/components/blacklight/response/facet_group_component_spec.rb +37 -0
  204. data/spec/components/blacklight/response/pagination_component_spec.rb +1 -1
  205. data/spec/components/blacklight/response/spellcheck_component_spec.rb +1 -1
  206. data/spec/components/blacklight/search_bar_component_spec.rb +28 -5
  207. data/spec/components/blacklight/search_context/server_applied_params_component_spec.rb +2 -2
  208. data/spec/components/blacklight/search_context/server_item_pagination_component_spec.rb +3 -5
  209. data/spec/components/blacklight/skip_link_component_spec.rb +8 -11
  210. data/spec/components/blacklight/start_over_button_component_spec.rb +4 -4
  211. data/spec/components/blacklight/system/dropdown_component_spec.rb +26 -0
  212. data/spec/components/blacklight/system/flash_message_component_spec.rb +7 -11
  213. data/spec/controllers/blacklight/catalog_spec.rb +1 -1
  214. data/spec/controllers/catalog_controller_spec.rb +12 -20
  215. data/spec/features/advanced_search_spec.rb +42 -21
  216. data/spec/features/facets_spec.rb +84 -12
  217. data/spec/features/modal_spec.rb +1 -1
  218. data/spec/features/search_filters_spec.rb +6 -4
  219. data/spec/features/search_spec.rb +3 -3
  220. data/spec/helpers/blacklight/facets_helper_behavior_spec.rb +10 -0
  221. data/spec/lib/blacklight/configuration/facet_field_spec.rb +2 -2
  222. data/spec/lib/blacklight/parameters_spec.rb +12 -1
  223. data/spec/lib/blacklight/search_state/filter_field_spec.rb +18 -0
  224. data/spec/models/blacklight/configuration_spec.rb +178 -28
  225. data/spec/models/blacklight/solr/default_filter_query_builder_spec.rb +72 -0
  226. data/spec/models/blacklight/solr/document_spec.rb +0 -4
  227. data/spec/models/blacklight/solr/repository_spec.rb +37 -29
  228. data/spec/models/blacklight/solr/response/facets_spec.rb +86 -40
  229. data/spec/models/blacklight/solr/response/group_response_spec.rb +8 -5
  230. data/spec/models/blacklight/solr/response/group_spec.rb +9 -5
  231. data/spec/models/blacklight/solr/response_spec.rb +96 -64
  232. data/spec/models/blacklight/solr/search_builder_behavior_spec.rb +38 -57
  233. data/spec/models/solr_document_spec.rb +5 -1
  234. data/spec/presenters/blacklight/constraint_presenter_spec.rb +32 -0
  235. data/spec/presenters/blacklight/document_presenter_spec.rb +3 -3
  236. data/spec/presenters/blacklight/facet_item_presenter_spec.rb +0 -7
  237. data/spec/presenters/blacklight/field_presenter_spec.rb +103 -22
  238. data/spec/presenters/blacklight/json_presenter_spec.rb +17 -0
  239. data/spec/presenters/blacklight/rendering/pipeline_spec.rb +130 -14
  240. data/spec/services/blacklight/search_service_spec.rb +6 -27
  241. data/spec/spec_helper.rb +0 -1
  242. data/spec/support/presenter_test_helpers.rb +1 -1
  243. data/spec/support/view_component_test_helpers.rb +0 -18
  244. data/spec/views/catalog/facet.html.erb_spec.rb +10 -3
  245. data/spec/views/catalog/index.atom.builder_spec.rb +8 -3
  246. data/spec/views/catalog/index.html.erb_spec.rb +3 -1
  247. metadata +69 -38
  248. data/.github/workflows/ruby.yml +0 -98
  249. data/app/assets/stylesheets/blacklight/_icons.scss +0 -4
  250. data/app/components/blacklight/facet_field_list_component.html.erb +0 -19
  251. data/app/components/blacklight/search/facet_suggest_input.html.erb +0 -9
  252. data/app/components/blacklight/search/facet_suggest_input.rb +0 -16
  253. data/app/javascript/blacklight-frontend/modalForm.js +0 -60
  254. data/app/views/catalog/_facet_index_navigation.html.erb +0 -1
  255. data/app/views/catalog/_facet_layout.html.erb +0 -8
  256. data/app/views/catalog/_facet_pagination.html.erb +0 -1
  257. data/app/views/catalog/_facet_pivot.html.erb +0 -3
  258. data/app/views/shared/_sitelinks_search_box.html.erb +0 -12
  259. data/spec/components/blacklight/document_metadata_component_spec.rb +0 -0
  260. data/spec/components/blacklight/search/facet_suggest_input_spec.rb +0 -33
  261. data/spec/features/sitelinks_search_box_spec.rb +0 -13
  262. data/spec/views/catalog/_facet_index_navigation.html.erb_spec.rb +0 -43
  263. data/spec/views/catalog/_facet_layout.html.erb_spec.rb +0 -41
@@ -8,6 +8,14 @@ class Blacklight::Configuration
8
8
  # @return [Class] document presenter class used by helpers and views
9
9
  # @!attribute document_component
10
10
  # @return [Class] component class used to render a document; defaults to Blacklight::DocumentComponent
11
+ # @!attribute document_title_component
12
+ # @return [Class] component class used to render a document title
13
+ # @!attribute document_metadata_component
14
+ # @return [Class] component class used to render the document metadata
15
+ # @!attribute document_thumbnail_component
16
+ # @return [Class] component class used to render a document thumbnail
17
+ # @!attribute document_embed_component
18
+ # @return [Class] component class used to render a document embed
11
19
  # @!attribute title_field
12
20
  # @return [String, Symbol] solr field to use to render a document title
13
21
  # @!attribute display_type_field
@@ -24,7 +32,7 @@ class Blacklight::Configuration
24
32
  # @return [Class] component class used to render the search bar
25
33
  # @!attribute search_header_component
26
34
  # @return [Class] component class used to render the header above the documents
27
- def display_label(**options)
35
+ def display_label(**)
28
36
  I18n.t(
29
37
  :"blacklight.search.view_title.#{key}",
30
38
  default: [
@@ -33,7 +41,7 @@ class Blacklight::Configuration
33
41
  title,
34
42
  key.to_s.humanize
35
43
  ],
36
- **options
44
+ **
37
45
  )
38
46
  end
39
47
 
@@ -46,19 +54,33 @@ class Blacklight::Configuration
46
54
  end
47
55
  end
48
56
 
57
+ # Provide backwards compatibility with the configuration keys without the document_ prefix
58
+ def title_component(*) = document_title_component(*)
59
+ def metadata_component(*) = document_metadata_component(*)
60
+ def thumbnail_component(*) = document_thumbnail_component(*)
61
+ def embed_component(*) = document_embed_component(*)
62
+
63
+ def title_component=(value)
64
+ self.document_title_component = value
65
+ end
66
+
67
+ def metadata_component=(value)
68
+ self.document_metadata_component = value
69
+ end
70
+
71
+ def thumbnail_component=(value)
72
+ self.document_thumbnail_component = value
73
+ end
74
+
75
+ def embed_component=(value)
76
+ self.document_embed_component = value
77
+ end
78
+
49
79
  class Show < ViewConfig
50
80
  # @!attribute route
51
81
  # @return [Hash] Default route parameters for 'show' requests.
52
82
  # Set this to a hash with additional arguments to merge into the route,
53
83
  # or set `controller: :current` to route to the current controller.
54
-
55
- def document_presenter_class
56
- super || Blacklight::ShowPresenter
57
- end
58
-
59
- def to_h
60
- super.merge(document_presenter_class: document_presenter_class)
61
- end
62
84
  end
63
85
 
64
86
  class Index < ViewConfig
@@ -69,14 +91,6 @@ class Blacklight::Configuration
69
91
  # see Blacklight::Catalog#additional_response_formats for information about the OpenStruct data
70
92
  # @!attribute collection_actions
71
93
  # @return [String, Symbol]
72
-
73
- def document_presenter_class
74
- super || Blacklight::IndexPresenter
75
- end
76
-
77
- def to_h
78
- super.merge(document_presenter_class: document_presenter_class)
79
- end
80
94
  end
81
95
  end
82
96
  end
@@ -47,7 +47,6 @@ module Blacklight
47
47
  property :header_component, default: Blacklight::HeaderComponent
48
48
  property :full_width_layout, default: false
49
49
 
50
- # bootstrap_version may be set to 4 or 5
51
50
  bootstrap_version = ENV['BOOTSTRAP_VERSION'].presence || "5"
52
51
  property :bootstrap_version, default: /(\d)(?:\.\d){0,2}/.match(bootstrap_version)[1].to_i
53
52
 
@@ -66,9 +65,6 @@ module Blacklight
66
65
 
67
66
  # === Single document request configuration
68
67
 
69
- # @!attribute document_solr_request_handler
70
- # @return [String] The solr request handler to use when requesting only a single document
71
- property :document_solr_request_handler, default: nil
72
68
  # @!attribute document_solr_path
73
69
  # @since v5.2.0
74
70
  # @return [String] The url path (relative to the solr base url) to use when requesting only a single document
@@ -76,7 +72,8 @@ module Blacklight
76
72
  # @!attribute json_solr_path
77
73
  # @since v7.34.0
78
74
  # @return [String] The url path (relative to the solr base url) to use when using Solr's JSON Query DSL (as with the advanced search)
79
- property :json_solr_path, default: 'advanced'
75
+ # @note You can configure a separate custom 'advanced' requestHandler in solrconfig.xml if desired, but it isn't necessary; the default 'select' handler will work.
76
+ property :json_solr_path, default: 'select'
80
77
  # @!attribute document_unique_id_param
81
78
  # @since v5.2.0
82
79
  # @return [Symbol] The solr query parameter used for sending the unique identifiers for one or more documents
@@ -101,7 +98,8 @@ module Blacklight
101
98
 
102
99
  # @!attribute repository_class
103
100
  # @return [Class] Class for sending and receiving requests from a search index
104
- property :repository_class, default: Blacklight::Solr::Repository
101
+ # defaults to the class configured in blacklight.yml
102
+ property :repository_class, default: Blacklight.repository_class
105
103
  # @!attribute search_builder_class
106
104
  # @return [Class] class for converting Blacklight parameters to request parameters for the repository_class
107
105
  property :search_builder_class, default: ::SearchBuilder
@@ -146,9 +144,15 @@ module Blacklight
146
144
  # @return [Blacklight::Configuration::ViewConfig::Index]
147
145
  property :index, default: ViewConfig::Index.new(
148
146
  # document presenter class used by helpers and views
149
- document_presenter_class: nil,
147
+ document_presenter_class: Blacklight::IndexPresenter,
148
+ # document presenter used for json responses
149
+ json_presenter_class: Blacklight::JsonPresenter,
150
150
  # component class used to render a document
151
151
  document_component: Blacklight::DocumentComponent,
152
+ document_embed_component: nil,
153
+ document_metadata_component: Blacklight::DocumentMetadataComponent,
154
+ document_thumbnail_component: Blacklight::Document::ThumbnailComponent,
155
+ document_title_component: Blacklight::DocumentTitleComponent,
152
156
  sidebar_component: Blacklight::Search::SidebarComponent,
153
157
  dropdown_component: Blacklight::System::DropdownComponent,
154
158
  # solr field to use to render a document title
@@ -165,6 +169,10 @@ module Blacklight
165
169
  respond_to: OpenStructWithHashAccess.new,
166
170
  # component class used to render the facet grouping
167
171
  facet_group_component: Blacklight::Response::FacetGroupComponent,
172
+ # component class used to render the facet search and start at
173
+ facet_filters_component: Blacklight::Facets::FiltersComponent,
174
+ # component class used to render the facet pagination
175
+ facet_pagination_component: Blacklight::FacetFieldPaginationComponent,
168
176
  # component class used to render search constraints
169
177
  constraints_component: Blacklight::ConstraintsComponent,
170
178
  # component class used to render the search bar
@@ -180,8 +188,9 @@ module Blacklight
180
188
  # @return [Blacklight::Configuration::ViewConfig::Show]
181
189
  property :show, default: ViewConfig::Show.new(
182
190
  # document presenter class used by helpers and views
183
- document_presenter_class: nil,
191
+ document_presenter_class: Blacklight::ShowPresenter,
184
192
  document_component: Blacklight::DocumentComponent,
193
+ document_thumbnail_component: nil,
185
194
  show_tools_component: Blacklight::Document::ShowToolsComponent,
186
195
  show_header_tools_component: nil,
187
196
  document_header_component: Blacklight::Document::PageHeaderComponent,
@@ -262,6 +271,10 @@ module Blacklight
262
271
  # @since v5.10.0
263
272
  # @return [Integer]
264
273
  property :default_facet_limit, default: 10
274
+ # @!attribute default_facet_suggest
275
+ # @since v9.0.0
276
+ # @return [Boolean]
277
+ property :default_facet_suggest, default: true
265
278
  # @!attribute default_more_limit
266
279
  # @since v7.0.0
267
280
  # @return [Integer]
@@ -292,8 +305,13 @@ module Blacklight
292
305
 
293
306
  # @!attribute advanced_search
294
307
  # @since v7.15.0
295
- # @return [#enabled]
296
- property :advanced_search, default: OpenStruct.new(enabled: false)
308
+ # @return [OpenStructWithHashAccess] Configuration for advanced search, including:
309
+ # enabled: (Boolean) whether advanced search is enabled
310
+ # form_solr_parameters: (Hash) optional parameters to send to Solr for the advanced search
311
+ # form; can override values that are set automatically via the
312
+ # #copy_facet_field_config_to_advanced! method
313
+ property :advanced_search, default: OpenStructWithHashAccess.new(enabled: true,
314
+ form_solr_parameters: {})
297
315
 
298
316
  # @!attribute enable_search_bar_autofocus
299
317
  # @since v7.2.0
@@ -450,6 +468,42 @@ module Blacklight
450
468
  facet_fields.map { |_facet, opts| opts[:group] }.uniq
451
469
  end
452
470
 
471
+ # Use existing search field configs to automatically prepare fields for use
472
+ # by the advanced search form.
473
+ def copy_search_field_config_to_advanced!
474
+ search_fields.each_value do |field|
475
+ next if field.include_in_advanced_search == false
476
+ next if field.clause_params
477
+
478
+ field.clause_params = {}
479
+ field.clause_params[:edismax] = field.solr_parameters.dup || {}
480
+ end
481
+ end
482
+
483
+ # Use existing facet field configs to automatically prepare fields for use
484
+ # by the advanced search form. If more specific config is needed, e.g., to
485
+ # set the facet limit for one field to a value other than -1, it can be
486
+ # expressed in the configuration in advanced_search.form_solr_parameters
487
+ def copy_facet_field_config_to_advanced!
488
+ advanced_search.form_solr_parameters ||= {}
489
+ advanced_search.form_solr_parameters['facet.sort'] ||= 'count'
490
+ advanced_search.form_solr_parameters['facet.field'] ||= []
491
+
492
+ facet_fields.each_value do |field|
493
+ next if field.include_in_advanced_search == false
494
+ # Skip query-type and pivot facets that can't be requested via facet.field
495
+ next if field.query || field.pivot || field.range
496
+
497
+ # Add the facet field to the advanced search configuration
498
+ advanced_search.form_solr_parameters['facet.field'] << field.field unless
499
+ advanced_search.form_solr_parameters['facet.field'].include?(field.field)
500
+
501
+ # Set the facet field's limit to -1 to show ALL values in advanced search
502
+ advanced_search.form_solr_parameters["f.#{field.field}.facet.limit"] = -1 unless
503
+ advanced_search.form_solr_parameters["f.#{field.field}.facet.limit"]
504
+ end
505
+ end
506
+
453
507
  # Add any configured facet fields to the default solr parameters hash
454
508
  # @overload add_facet_fields_to_solr_request!
455
509
  # add all facet fields to the solr request
@@ -114,7 +114,7 @@ module Blacklight
114
114
 
115
115
  def set_default_proc!
116
116
  self.default_proc = lambda do |hash, key|
117
- hash[key] = nested_class.new(key: key)
117
+ hash[key] = nested_class.new({ key: key })
118
118
  end
119
119
  end
120
120
  end
@@ -57,7 +57,7 @@ module Blacklight
57
57
  self.class.new @table.deep_transform_values(&)
58
58
  end
59
59
 
60
- def try(method_name = nil, *args, &)
60
+ def try(method_name = nil, *, &)
61
61
  if method_name.nil? && block_given?
62
62
  if b.arity.zero?
63
63
  instance_eval(&)
@@ -65,7 +65,7 @@ module Blacklight
65
65
  yield self
66
66
  end
67
67
  elsif respond_to?(method_name)
68
- public_send(method_name, *args, &b)
68
+ public_send(method_name, *, &b)
69
69
  end
70
70
  end
71
71
  end
@@ -18,7 +18,7 @@ module Blacklight
18
18
  mapper.get "opensearch"
19
19
  mapper.get 'suggest', as: 'suggest_index'
20
20
  mapper.get "facet/:id", action: 'facet', as: 'facet'
21
- mapper.get "facet_suggest/:id/(:query_fragment)", action: 'facet', as: 'facet_suggest', defaults: { only_values: true }
21
+ mapper.get "facet_suggest/:id", action: 'facet', as: 'facet_suggest', defaults: { only_values: true }
22
22
  end
23
23
  end
24
24
  end
@@ -12,7 +12,7 @@ module Blacklight
12
12
  attr_reader :processor_chain, :search_state, :blacklight_params
13
13
 
14
14
  # @overload initialize(scope)
15
- # @param [Object] scope scope the scope where the filter methods reside in.
15
+ # @param [Object] scope the scope where the filter methods reside in.
16
16
  # @overload initialize(processor_chain, scope)
17
17
  # @param [List<Symbol>,TrueClass] processor_chain options a list of filter methods to run or true, to use the default methods
18
18
  # @param [Object] scope the scope where the filter methods reside in.
@@ -59,6 +59,7 @@ module Blacklight
59
59
 
60
60
  ##
61
61
  # Append additional processor chain directives
62
+ # This is used in blacklight_range_limit
62
63
  def append(*addl_processor_chain)
63
64
  params_will_change!
64
65
  builder = self.class.new(processor_chain + addl_processor_chain, scope)
@@ -120,8 +120,8 @@ module Blacklight
120
120
  delegate :any?, to: :values
121
121
 
122
122
  # Appease rubocop rules by implementing #each_value
123
- def each_value(except: [], &block)
124
- values(except: except).each(&block)
123
+ def each_value(except: [], &)
124
+ values(except: except).each(&)
125
125
  end
126
126
 
127
127
  # @param [String,#value] item a filter to remove from the url
@@ -145,8 +145,8 @@ module Blacklight
145
145
  def permitted_params
146
146
  if config.pivot
147
147
  {
148
- filters_key => config.pivot.each_with_object({}) { |key, filter| filter.merge(key => [], "-#{key}" => []) },
149
- inclusive_filters_key => config.pivot.each_with_object({}) { |key, filter| filter.merge(key => []) }
148
+ filters_key => config.pivot.each_with_object({}) { |key, filter| filter.merge!(key => [], "-#{key}" => []) },
149
+ inclusive_filters_key => config.pivot.each_with_object({}) { |key, filter| filter.merge!(key => []) }
150
150
  }
151
151
  else
152
152
  {
@@ -89,20 +89,20 @@ module Blacklight
89
89
  end
90
90
  end
91
91
 
92
- class QueryBuilder
92
+ class QueryBuilder < Solr::AbstractFilterQueryBuilder
93
93
  # @return [Array] filter_query, subqueries
94
- def self.call(search_builder, filter, solr_parameters)
94
+ def call(filter, solr_parameters)
95
95
  existing = solr_parameters['fq']&.dup || []
96
96
  queries = []
97
97
  filter.values.compact_blank.each do |value|
98
- queries << search_builder.send(:facet_value_to_fq_string, filter.pivot.first, value.value)
98
+ queries << facet_value_to_fq_string(filter.pivot.first, value.value)
99
99
  value.fq.each do |entry|
100
100
  k, v = entry
101
- queries << search_builder.send(:facet_value_to_fq_string, k, v) if v
101
+ queries << facet_value_to_fq_string(k, v) if v
102
102
  end
103
103
  queries.uniq!
104
104
  end
105
- [(queries - existing)]
105
+ [queries - existing]
106
106
  end
107
107
  end
108
108
 
@@ -82,6 +82,8 @@ module Blacklight
82
82
  blacklight_config.facet_fields.each_value.map { |value| filter(value) }
83
83
  end
84
84
 
85
+ # Return the list of filters (i.e. facets) that have been applied in the current search
86
+ # @return [Array<FilterField>]
85
87
  def filters
86
88
  @filters ||= filter_fields.select(&:any?)
87
89
  end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Blacklight::Solr
4
+ class AbstractFilterQueryBuilder
5
+ def initialize(blacklight_config:)
6
+ @blacklight_config = blacklight_config
7
+ end
8
+
9
+ attr_reader :blacklight_config
10
+
11
+ private
12
+
13
+ def facet_inclusive_value_to_fq_string(facet_field, values)
14
+ return if values.blank?
15
+
16
+ return facet_value_to_fq_string(facet_field, values.first) if values.length == 1
17
+
18
+ facet_config = blacklight_config.facet_fields[facet_field]
19
+
20
+ local_params = []
21
+ local_params << "tag=#{facet_config.tag}" if facet_config&.tag
22
+
23
+ solr_filters = values.each_with_object({}).with_index do |(v, h), index|
24
+ h["f_inclusive.#{facet_field}.#{index}"] = facet_value_to_fq_string(facet_field, v, use_local_params: false)
25
+ end
26
+
27
+ filter_query = solr_filters.keys.map do |k|
28
+ "{!query v=$#{k}}"
29
+ end.join(' OR ')
30
+
31
+ ["{!lucene#{" #{local_params.join(' ')}" unless local_params.empty?}}#{filter_query}", solr_filters]
32
+ end
33
+
34
+ ##
35
+ # Convert a facet/value pair into a solr fq parameter
36
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
37
+ def facet_value_to_fq_string(facet_field, value, use_local_params: true)
38
+ facet_config = blacklight_config.facet_fields[facet_field]
39
+
40
+ solr_field = facet_config.field if facet_config && !facet_config.query
41
+ solr_field ||= facet_field
42
+
43
+ local_params = []
44
+ local_params << "tag=#{facet_config.tag}" if use_local_params && facet_config&.tag
45
+
46
+ if facet_config&.query
47
+ if facet_config.query[value]
48
+ facet_config.query[value][:fq]
49
+ else
50
+ # exclude all documents if the custom facet key specified was not found
51
+ '-*:*'
52
+ end
53
+ elsif value.is_a?(Range)
54
+ prefix = "{!#{local_params.join(' ')}}" unless local_params.empty?
55
+ start = value.begin || '*'
56
+ finish = value.end || '*'
57
+ "#{prefix}#{solr_field}:[#{start} TO #{finish}]"
58
+ elsif value == Blacklight::SearchState::FilterField::MISSING
59
+ "-#{solr_field}:[* TO *]"
60
+ else
61
+ "{!term f=#{solr_field}#{" #{local_params.join(' ')}" unless local_params.empty?}}#{convert_to_term_value(value)}"
62
+ end
63
+ end
64
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
65
+
66
+ def convert_to_term_value(value)
67
+ case value
68
+ when DateTime, Time
69
+ value.utc.strftime("%Y-%m-%dT%H:%M:%SZ")
70
+ when Date
71
+ value.to_time(:local).strftime("%Y-%m-%dT%H:%M:%SZ")
72
+ else
73
+ value.to_s
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Blacklight::Solr
4
+ class DefaultFilterQueryBuilder < AbstractFilterQueryBuilder
5
+ def call(filter, _solr_parameters)
6
+ filter_queries = []
7
+ all_subqueries = {}
8
+ filter.values.compact_blank.each do |value|
9
+ filter_query, subqueries = if value.is_a?(Array)
10
+ facet_inclusive_value_to_fq_string(filter.key, value.compact_blank)
11
+ else
12
+ facet_value_to_fq_string(filter.config.key, value)
13
+ end
14
+ filter_queries << filter_query
15
+ all_subqueries.merge!(subqueries) if subqueries
16
+ end
17
+ [filter_queries, all_subqueries]
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Blacklight::Solr
4
+ class FieldReflectionSearchBuilder < SearchBuilder
5
+ self.default_processor_chain = [:add_params]
6
+
7
+ def add_params(request)
8
+ request.reverse_merge!({ fl: '*', 'json.nl' => 'map' })
9
+ end
10
+ end
11
+ end
@@ -7,9 +7,7 @@ module Blacklight::Solr
7
7
  # @param [String] id document's unique key value
8
8
  # @param [Hash] params additional solr query parameters
9
9
  def find id, params = {}
10
- doc_params = params.reverse_merge(blacklight_config.default_document_solr_params)
11
- .reverse_merge(qt: blacklight_config.document_solr_request_handler)
12
- .merge(blacklight_config.document_unique_id_param => id)
10
+ doc_params = SingleDocSearchBuilder.new(self, id, params)
13
11
 
14
12
  solr_response = send_and_receive blacklight_config.document_solr_path || blacklight_config.solr_path, doc_params
15
13
  raise Blacklight::Exceptions::RecordNotFound if solr_response.documents.empty?
@@ -25,10 +23,14 @@ module Blacklight::Solr
25
23
 
26
24
  ##
27
25
  # Execute a search query against solr
28
- # @param [Hash] params solr query parameters
26
+ # @param [Hash,Blacklight::SearchBuilder] params solr query parameters
29
27
  # @param [String] path solr request handler path
30
- def search pos_params = {}, path: nil, params: nil, **kwargs
31
- request_params = (params || pos_params).reverse_merge(kwargs).reverse_merge({ qt: blacklight_config.qt })
28
+ def search pos_params = nil, path: nil, params: nil, **kwargs
29
+ if pos_params
30
+ Blacklight.deprecation.warn("Passing positional arguments to search() is deprecated. Use the params kwarg instead.")
31
+ end
32
+
33
+ request_params = (params || pos_params || {}).reverse_merge(kwargs).reverse_merge({ qt: blacklight_config.qt })
32
34
 
33
35
  send_and_receive(path || default_search_path(request_params), request_params)
34
36
  end
@@ -44,27 +46,27 @@ module Blacklight::Solr
44
46
  # Gets a list of available fields
45
47
  # @return [Hash]
46
48
  def reflect_fields
47
- send_and_receive('admin/luke', params: { fl: '*', 'json.nl' => 'map' })['fields']
49
+ doc_params = FieldReflectionSearchBuilder.new(self)
50
+ send_and_receive('admin/luke', doc_params)['fields']
48
51
  end
49
52
 
50
53
  ##
51
54
  # @return [boolean] true if the repository is reachable
52
- def ping
55
+ def ping?
53
56
  response = connection.send_and_receive 'admin/ping', {}
54
57
  Blacklight.logger&.info("Ping [#{connection.uri}] returned: '#{response['status']}'")
55
58
  response['status'] == "OK"
56
59
  end
57
60
 
61
+ alias ping ping?
62
+ Blacklight.deprecation.deprecate_methods(Repository, ping: 'use Repository#ping? instead')
63
+
58
64
  ##
59
- # Execute a solr query
65
+ # Execute a solr query at the given path with the parameters
60
66
  # TODO: Make this private after we have a way to abstract admin/luke and ping
61
67
  # @see [RSolr::Client#send_and_receive]
62
- # @overload find(solr_path, params)
63
- # Execute a solr query at the given path with the parameters
64
- # @param [String] solr path (defaults to blacklight_config.solr_path)
65
- # @param [Hash] parameters for RSolr::Client#send_and_receive
66
- # @overload find(params)
67
- # @param [Hash] parameters for RSolr::Client#send_and_receive
68
+ # @param [String] path solr path (defaults to blacklight_config.solr_path)
69
+ # @param [Hash, Blacklight::SearchBuilder] solr_params parameters for RSolr::Client#send_and_receive
68
70
  # @return [Blacklight::Solr::Response] the solr response object
69
71
  def send_and_receive(path, solr_params = {})
70
72
  benchmark("Solr fetch", level: :debug) do
@@ -229,7 +229,7 @@ module Blacklight::Solr::Response::Facets
229
229
 
230
230
  blacklight_config.facet_fields.select { |_k, v| v.query }.each_with_object({}) do |(field_name, facet_field), hash|
231
231
  salient_facet_queries = facet_field.query.map { |_k, x| x[:fq] }
232
- items = facet_queries.select { |k, _v| salient_facet_queries.include?(k) }.reject { |_value, hits| hits.zero? }.map do |value, hits|
232
+ items = facet_queries.slice(*salient_facet_queries).reject { |_value, hits| hits.zero? }.map do |value, hits|
233
233
  salient_fields = facet_field.query.select { |_key, val| val[:fq] == value }
234
234
  key = ((salient_fields.keys if salient_fields.respond_to? :keys) || salient_fields.first).first
235
235
  Blacklight::Solr::Response::Facets::FacetItem.new(value: key, hits: hits, label: facet_field.query[key][:label])
@@ -250,7 +250,7 @@ module Blacklight::Solr::Response::Facets
250
250
 
251
251
  salient_facet_queries = facet_field.query.map { |_k, x| x[:fq] }
252
252
 
253
- relevant_facet_data = self['facets'].select { |k, _v| salient_facet_queries.include?(k) }.reject { |_key, data| data['count'].zero? }
253
+ relevant_facet_data = self['facets'].slice(*salient_facet_queries).reject { |_key, data| data['count'].zero? }
254
254
 
255
255
  relevant_facet_data.map do |key, data|
256
256
  salient_fields = facet_field.query.select { |_key, val| val[:fq] == key }
@@ -52,10 +52,6 @@ module Blacklight::Solr::Response::Params
52
52
 
53
53
  private
54
54
 
55
- def search_builder
56
- request_params if request_params.is_a?(Blacklight::SearchBuilder)
57
- end
58
-
59
55
  # Extract JSON Request API parameters from the response header or the request itself
60
56
  def json_params
61
57
  encoded_json_params = header&.dig('params', 'json')
@@ -8,12 +8,16 @@ class Blacklight::Solr::Response < ActiveSupport::HashWithIndifferentAccess
8
8
  include MoreLikeThis
9
9
  include Params
10
10
 
11
- attr_reader :request_params
11
+ attr_reader :request_params, :search_builder
12
12
  attr_accessor :blacklight_config, :options
13
13
 
14
14
  delegate :document_factory, to: :blacklight_config
15
15
 
16
+ # @param [Hash] data
17
+ # @param [Hash, Blacklight::SearchBuilder] request_params a SearchBuilder or a Hash of parameters
16
18
  def initialize(data, request_params, options = {})
19
+ @search_builder = request_params if request_params.is_a?(Blacklight::SearchBuilder)
20
+
17
21
  super(force_to_utf8(ActiveSupport::HashWithIndifferentAccess.new(data)))
18
22
  @request_params = ActiveSupport::HashWithIndifferentAccess.new(request_params)
19
23
  self.blacklight_config = options[:blacklight_config]