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
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Blacklight
4
+ module Facets
5
+ class NoLayoutComponent < Blacklight::Component
6
+ renders_one :label
7
+ renders_one :body
8
+
9
+ def initialize(**); end
10
+
11
+ def call
12
+ body.to_s
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Blacklight
4
+ module Facets
5
+ class PivotListComponent < Blacklight::Facets::ListComponent
6
+ def initialize(facet_field:,
7
+ classes: %w[pivot-facet facet-values list-unstyled],
8
+ role: 'tree',
9
+ layout: nil)
10
+ super
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Blacklight
4
+ module Facets
5
+ # Standard display of a selected facet value (e.g. without a link and with a remove button)
6
+ class SelectedValueComponent < Blacklight::Component
7
+ def initialize(label:, href:)
8
+ @label = label
9
+ @href = href
10
+ super()
11
+ end
12
+
13
+ attr_reader :label, :href
14
+
15
+ def call
16
+ tag.span(class: "facet-label") do
17
+ tag.span(label, class: "selected") + remove_link
18
+ end
19
+ end
20
+
21
+ def remove_link
22
+ link_to(href, class: "remove ps-2", rel: "nofollow") do
23
+ render(Blacklight::Icons::RemoveComponent.new(aria_hidden: true)) +
24
+ tag.span(t(:'blacklight.search.facets.selected.remove'), class: 'visually-hidden')
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,17 @@
1
+ <div class="input-group">
2
+ <label class="input-group-text" for="facet_suggest_<%= key %>">
3
+ <%= I18n.t('blacklight.search.facets.suggest.label', field_label: label.downcase.pluralize) %>
4
+ </label>
5
+ <%= search_field_tag "facet_suggest_#{key}",
6
+ nil,
7
+ class: "facet-suggest form-control",
8
+ data: {
9
+ facet_field: key,
10
+ facet_search_context: helpers.search_facet_path(id: key)
11
+ },
12
+ placeholder: I18n.t('blacklight.search.facets.suggest.placeholder')
13
+ %>
14
+ <span class="input-group-text">
15
+ <%= render Blacklight::Icons::SearchComponent.new %>
16
+ </span>
17
+ </div>
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Blacklight
4
+ module Facets
5
+ class SuggestComponent < Blacklight::Component
6
+ def initialize(presenter:)
7
+ @presenter = presenter
8
+ end
9
+
10
+ private
11
+
12
+ attr_accessor :presenter
13
+
14
+ delegate :key, :label, to: :presenter
15
+
16
+ def render?
17
+ presenter.suggest?
18
+ end
19
+ end
20
+ end
21
+ end
@@ -19,8 +19,8 @@ module Blacklight
19
19
  # Hack so that the default lambdas are triggered
20
20
  # so that we don't have to do c.with_top_bar() in the call.
21
21
  def before_render
22
- set_slot(:top_bar, nil) unless top_bar
23
- set_slot(:search_bar, nil) unless search_bar
22
+ with_top_bar unless top_bar
23
+ with_search_bar unless search_bar
24
24
  end
25
25
  end
26
26
  end
@@ -7,8 +7,8 @@ module Blacklight
7
7
  # Blacklight::Icons::RemoveComponent.svg = '<svg>your SVG here</svg>'
8
8
  class RemoveComponent < Blacklight::Icons::IconComponent
9
9
  self.svg = <<~SVG
10
- <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-x fs-4" viewBox="0 0 16 16">
11
- <path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708"/>
10
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-x-lg" viewBox="0 0 16 16">
11
+ <path d="M2.146 2.854a.5.5 0 1 1 .708-.708L8 7.293l5.146-5.147a.5.5 0 0 1 .708.708L8.707 8l5.147 5.146a.5.5 0 0 1-.708.708L8 8.707l-5.146 5.147a.5.5 0 0 1-.708-.708L7.293 8z"/>
12
12
  </svg>
13
13
  SVG
14
14
  end
@@ -2,7 +2,7 @@
2
2
  <% component.with_label do %>
3
3
  <%= label %>
4
4
  <% end %>
5
- <% component.with_value do %>
6
- <%= render_field %>
5
+ <% render_field_values.each_with_index do |value, index| %>
6
+ <% component.with_value(value: value, index: index) %>
7
7
  <% end %>
8
8
  <% end %>
@@ -27,7 +27,8 @@ module Blacklight
27
27
  end
28
28
 
29
29
  # Override this method in a subclass to change the way this value is rendered
30
- def render_field
30
+ # @return [Array]
31
+ def render_field_values
31
32
  @field.render
32
33
  end
33
34
 
@@ -4,23 +4,28 @@ module Blacklight
4
4
  class MetadataFieldLayoutComponent < Blacklight::Component
5
5
  with_collection_parameter :field
6
6
  renders_one :label
7
- renders_many :values, (lambda do |value: nil, &block|
7
+ renders_many :values, (lambda do |index:, value: nil, &block|
8
+ classes = [@value_class, "blacklight-#{@key}"]
9
+ classes.unshift @offset_class unless index.zero?
10
+ classes.join(' ')
11
+
8
12
  if @value_tag.nil?
9
13
  block&.call || value
10
14
  elsif block
11
- content_tag @value_tag, class: "#{@value_class} blacklight-#{@key}", &block
15
+ content_tag @value_tag, class: classes, &block
12
16
  else
13
- content_tag @value_tag, value, class: "#{@value_class} blacklight-#{@key}"
17
+ content_tag @value_tag, value, class: classes
14
18
  end
15
19
  end)
16
20
 
17
21
  # @param field [Blacklight::FieldPresenter]
18
- def initialize(field:, value_tag: 'dd', label_class: 'col-md-3', value_class: 'col-md-9')
22
+ def initialize(field:, value_tag: 'dd', label_class: 'col-md-3', value_class: 'col-md-9', offset_class: 'offset-md-3')
19
23
  @field = field
20
24
  @key = @field.key.parameterize
21
25
  @label_class = label_class
22
26
  @value_tag = value_tag
23
27
  @value_class = value_class
28
+ @offset_class = offset_class
24
29
  end
25
30
  end
26
31
  end
@@ -4,8 +4,8 @@ module Blacklight
4
4
  class MetadataFieldPlainTextLayoutComponent < Blacklight::MetadataFieldLayoutComponent
5
5
  with_collection_parameter :field
6
6
 
7
- def initialize(field:, **kwargs)
8
- super(field: field, **kwargs, value_tag: nil)
7
+ def initialize(field:, **)
8
+ super(field: field, **, value_tag: nil)
9
9
  end
10
10
 
11
11
  # rubocop:disable Rails/OutputSafety
@@ -1,12 +1,12 @@
1
1
  <% # main container for facets/limits menu -%>
2
- <%= content_tag :div, id: @id, class: 'facets sidenav facets-toggleable-md' do %>
2
+ <%= content_tag :div, id: @id, class: container_classes do %>
3
3
  <div class="facets-header">
4
- <%= content_tag :h2, @title, class: 'facets-heading h4' if @title %>
4
+ <%= content_tag :h2, @title, class: header_classes if @title %>
5
5
 
6
6
  <%= collapse_toggle_button(@panel_id) %>
7
7
  </div>
8
8
 
9
- <div id="<%= @panel_id %>" class="facets-collapse d-lg-block collapse accordion">
9
+ <div id="<%= @panel_id %>" class="<%= body_classes %>">
10
10
  <%= body %>
11
11
  </div>
12
12
  <% end %>
@@ -8,13 +8,20 @@ module Blacklight
8
8
 
9
9
  # @param [String] id a unique identifier for the group
10
10
  # @param [String] title the title of the facet group section
11
- def initialize(id:, title: nil)
11
+ def initialize(id:, title: nil, body_classes: 'facets-collapse d-lg-block collapse accordion',
12
+ header_classes: 'facets-heading h4',
13
+ container_classes: 'facets sidenav facets-toggleable-md')
12
14
  @groupname = id
13
15
  @id = id ? "facets-#{id}" : 'facets'
14
16
  @title = title || I18n.t("blacklight.search.#{@id}.title")
15
17
  @panel_id = id ? "facet-panel-#{id}-collapse" : 'facet-panel-collapse'
18
+ @body_classes = body_classes
19
+ @header_classes = header_classes
20
+ @container_classes = container_classes
16
21
  end
17
22
 
23
+ attr_accessor :body_classes, :header_classes, :container_classes
24
+
18
25
  def collapse_toggle_button(panel_id)
19
26
  render button_component.new(panel_id: panel_id)
20
27
  end
@@ -24,6 +31,7 @@ module Blacklight
24
31
  end
25
32
 
26
33
  def render?
34
+ # debugger
27
35
  body.present?
28
36
  end
29
37
  end
@@ -15,7 +15,7 @@
15
15
  options_for_select(search_fields, h(@search_field)),
16
16
  {},
17
17
  title: scoped_t('search_field.title'),
18
- class: "custom-select form-select search-field") %>
18
+ class: "form-select search-field") %>
19
19
  <% elsif search_fields.length == 1 %>
20
20
  <%= f.hidden_field :search_field, value: search_fields.first.last %>
21
21
  <% end %>
@@ -36,6 +36,6 @@
36
36
  <% end %>
37
37
 
38
38
  <% if advanced_search_enabled? %>
39
- <%= link_to t('blacklight.advanced_search.more_options'), @advanced_search_url, class: 'advanced_search btn btn-secondary'%>
39
+ <%= link_to t('blacklight.advanced_search.more_options'), @advanced_search_url, class: 'advanced_search btn btn-link text-body' %>
40
40
  <% end %>
41
41
  </search>
@@ -1,7 +1,7 @@
1
1
  <%= content_tag :div, id: @id, class: @classes.join(' ') do %>
2
2
  <%= button %>
3
3
 
4
- <div class="dropdown-menu" role="menu">
4
+ <div class="dropdown-menu">
5
5
  <% options.each do |option| %>
6
6
  <%= option %>
7
7
  <% end %>
@@ -6,7 +6,7 @@ module Blacklight
6
6
  renders_one :button, DropdownButtonComponent
7
7
 
8
8
  renders_many :options, (lambda do |text:, url:, selected: false|
9
- link_to(text, url, class: "dropdown-item #{'active' if selected}", role: 'menuitem', aria: { current: ('page' if selected) })
9
+ link_to(text, url, class: "dropdown-item #{'active' if selected}", aria: { current: ('page' if selected) })
10
10
  end)
11
11
 
12
12
  # rubocop:disable Metrics/ParameterLists
@@ -1,6 +1,6 @@
1
1
  <div class="alert alert-dismissible <%= @classes %>">
2
2
  <%= message %>
3
- <%= tag.button button_contents, type: "button", class: "btn-close",
3
+ <%= tag.button '', type: "button", class: "btn-close",
4
4
  data: { dismiss: "alert", bs_dismiss: "alert" },
5
5
  aria: { label: "Close" } %>
6
6
  </div>
@@ -16,15 +16,6 @@ module Blacklight
16
16
  with_message { @message } if @message
17
17
  end
18
18
 
19
- # Bootstrap 4 requires the span, but Bootstrap 5 should not have it.
20
- # See https://getbootstrap.com/docs/4.6/components/alerts/#dismissing
21
- # https://getbootstrap.com/docs/5.1/components/alerts/#dismissing
22
- def button_contents
23
- return if helpers.controller.blacklight_config.bootstrap_version == 5
24
-
25
- tag.span '&times;'.html_safe, aria: { hidden: true }
26
- end
27
-
28
19
  def alert_class(type)
29
20
  case type.to_s
30
21
  when 'success' then "alert-success"
@@ -6,8 +6,7 @@
6
6
  <h1 class="modal-title"><%= title %></h1>
7
7
  <% end) %>
8
8
 
9
- <button type="button" class="blacklight-modal-close btn-close close" data-bl-dismiss="modal" aria-label="<%= t('blacklight.modal.close') %>">
10
- <span aria-hidden="true" class="visually-hidden">&times;</span>
9
+ <button type="button" class="blacklight-modal-close btn-close" data-bl-dismiss="modal" aria-label="<%= t('blacklight.modal.close') %>">
11
10
  </button>
12
11
  </div>
13
12
 
@@ -1,7 +1,7 @@
1
- <nav class="navbar navbar-expand-md navbar-dark bg-dark topbar" aria-label="<%= aria_label %>">
1
+ <nav class="navbar navbar-expand-md bg-dark topbar" aria-label="<%= aria_label %>">
2
2
  <div class="<%= container_classes %>">
3
3
  <%= logo_link %>
4
- <button class="navbar-toggler" type="button" data-toggle="collapse" data-bs-toggle="collapse" data-target="#user-util-collapse" data-bs-target="#user-util-collapse" aria-controls="user-util-collapse" aria-expanded="false" aria-label="Toggle navigation">
4
+ <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#user-util-collapse" aria-controls="user-util-collapse" aria-expanded="false" aria-label="Toggle navigation">
5
5
  <span class="navbar-toggler-icon"></span>
6
6
  </button>
7
7
 
@@ -36,8 +36,8 @@ module Blacklight::Bookmarks
36
36
 
37
37
  # Blacklight uses #search_action_url to figure out the right URL for
38
38
  # the global search box
39
- def search_action_url *args
40
- search_catalog_url(*args)
39
+ def search_action_url(*)
40
+ search_catalog_url(*)
41
41
  end
42
42
 
43
43
  # @return [Hash] a hash of context information to pass through to the search service
@@ -85,6 +85,11 @@ module Blacklight::Bookmarks
85
85
  false
86
86
  end
87
87
 
88
+ create_response(success)
89
+ end
90
+
91
+ # Override the create_response method to handle the response appropriately.
92
+ def create_response(success)
88
93
  if request.xhr?
89
94
  success ? render(json: { bookmarks: { count: current_or_guest_user.bookmarks.count } }) : render(json: current_or_guest_user.errors.full_messages, status: :internal_server_error)
90
95
  else
@@ -110,9 +115,14 @@ module Blacklight::Bookmarks
110
115
 
111
116
  success = @bookmarks.all? do |bookmark|
112
117
  bookmark = current_or_guest_user.bookmarks.find_by(bookmark)
113
- bookmark && bookmark.delete && bookmark.destroyed?
118
+ bookmark&.delete && bookmark.destroyed?
114
119
  end
115
120
 
121
+ destroy_response(success)
122
+ end
123
+
124
+ # Override the destroy_response method to handle the response appropriately.
125
+ def destroy_response(success)
116
126
  if success
117
127
  if request.xhr?
118
128
  render(json: { bookmarks: { count: current_or_guest_user.bookmarks.count } })
@@ -15,7 +15,6 @@ module Blacklight::Catalog
15
15
  included do
16
16
  if respond_to? :helper_method
17
17
  helper_method :sms_mappings, :has_search_parameters?
18
- helper_method :search_facet_path
19
18
  end
20
19
 
21
20
  record_search_parameters
@@ -23,16 +22,13 @@ module Blacklight::Catalog
23
22
 
24
23
  # get search results from the solr index
25
24
  def index
26
- @response = search_service.search_results
25
+ @response = retrieve_search_results
27
26
 
28
27
  respond_to do |format|
29
28
  format.html { store_preferred_view }
30
29
  format.rss { render layout: false }
31
30
  format.atom { render layout: false }
32
- format.json do
33
- @presenter = Blacklight::JsonPresenter.new(@response,
34
- blacklight_config)
35
- end
31
+ format.json { @presenter = json_presenter(@response) }
36
32
  additional_response_formats(format)
37
33
  document_export_formats(format)
38
34
  end
@@ -80,17 +76,19 @@ module Blacklight::Catalog
80
76
 
81
77
  # displays values and pagination links for a single facet field
82
78
  def facet
79
+ # @facet is a Blacklight::Configuration::FacetField
83
80
  @facet = blacklight_config.facet_fields[params[:id]]
84
81
  raise ActionController::RoutingError, 'Not Found' unless @facet
85
82
 
86
- query_fragment = params[:query_fragment] || ''
87
- @response = if query_fragment.present?
83
+ @response = if params[:query_fragment].present?
88
84
  search_service.facet_suggest_response(@facet.key, params[:query_fragment])
89
85
  else
90
- @response = search_service.facet_field_response(@facet.key)
86
+ search_service.facet_field_response(@facet.key)
91
87
  end
88
+ # @display_facet is a Blacklight::Solr::Response::Facets::FacetField
92
89
  @display_facet = @response.aggregations[@facet.field]
93
90
 
91
+ # @presenter is a Blacklight::FacetFieldPresenter
94
92
  @presenter = @facet.presenter.new(@facet, @display_facet, view_context)
95
93
  @pagination = @presenter.paginator
96
94
  respond_to do |format|
@@ -139,16 +137,19 @@ module Blacklight::Catalog
139
137
  params[:search_field].present? || search_state.has_constraints?
140
138
  end
141
139
 
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
140
+ private
141
+
142
+ # @param [Blacklight::Solr::Response] repository_response
143
+ # @return [Blacklight::JsonPresenter]
144
+ def json_presenter(repository_response)
145
+ blacklight_config.index.json_presenter_class.new(repository_response, blacklight_config)
149
146
  end
150
147
 
151
- private
148
+ # This method may be overridden to customize search behavior.
149
+ # @return [Blacklight::Solr::Response] the solr response object
150
+ def retrieve_search_results
151
+ search_service.search_results
152
+ end
152
153
 
153
154
  #
154
155
  # non-routable methods ->
@@ -236,25 +237,17 @@ module Blacklight::Catalog
236
237
  # Email Action (this will render the appropriate view on GET requests and process the form and send the email on POST requests)
237
238
  def email_action documents
238
239
  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
240
+ mail.deliver_now
244
241
  end
245
242
 
246
243
  # SMS action (this will render the appropriate view on GET requests and process the form and send the email on POST requests)
247
244
  def sms_action documents
248
245
  to = "#{params[:to].gsub(/[^\d]/, '')}@#{params[:carrier]}"
249
246
  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
247
+ mail.deliver_now
255
248
  end
256
249
 
257
- def validate_sms_params
250
+ def sms_params_valid?
258
251
  if params[:to].blank?
259
252
  flash[:error] = I18n.t('blacklight.sms.errors.to.blank')
260
253
  elsif params[:carrier].blank?
@@ -267,12 +260,14 @@ module Blacklight::Catalog
267
260
 
268
261
  flash[:error].blank?
269
262
  end
263
+ alias validate_sms_params sms_params_valid?
264
+ Blacklight.deprecation.deprecate_methods(Blacklight::Catalog, validate_sms_params: 'use Catalog#sms_params_valid? instead')
270
265
 
271
266
  def sms_mappings
272
267
  Blacklight::Engine.config.blacklight.sms_mappings
273
268
  end
274
269
 
275
- def validate_email_params
270
+ def email_params_valid?
276
271
  if params[:to].blank?
277
272
  flash[:error] = I18n.t('blacklight.email.errors.to.blank')
278
273
  elsif !params[:to].match(Blacklight::Engine.config.blacklight.email_regexp)
@@ -281,6 +276,8 @@ module Blacklight::Catalog
281
276
 
282
277
  flash[:error].blank?
283
278
  end
279
+ alias validate_email_params email_params_valid?
280
+ Blacklight.deprecation.deprecate_methods(Blacklight::Catalog, validate_email_params: 'use Catalog#email_params_valid? instead')
284
281
 
285
282
  def start_new_search_session?
286
283
  action_name == "index"
@@ -293,7 +290,7 @@ module Blacklight::Catalog
293
290
  def blacklight_advanced_search_form_search_service
294
291
  form_search_state = search_state_class.new(blacklight_advanced_search_form_params, blacklight_config, self)
295
292
 
296
- search_service_class.new(config: blacklight_config, search_state: form_search_state, user_params: form_search_state.to_h, **search_service_context)
293
+ search_service_class.new(config: blacklight_config, search_state: form_search_state, **search_service_context)
297
294
  end
298
295
 
299
296
  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
 
@@ -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.
@@ -130,10 +130,12 @@ module Blacklight::CatalogHelperBehavior
130
130
  # @return [String]
131
131
  def render_search_to_page_title_filter(facet, values)
132
132
  facet_config = facet_configuration_for_field(facet)
133
- filter_label = facet_field_label(facet_config.key)
133
+ facet_presenter = facet_field_presenter(facet_config, {})
134
+ filter_label = facet_presenter.label
134
135
  filter_value = if values.size < 3
135
136
  values.map do |value|
136
- label = facet_item_presenter(facet_config, value, facet).label
137
+ item_presenter = facet_presenter.item_presenter(value)
138
+ label = item_presenter.label
137
139
  label = strip_tags(label) if label.html_safe?
138
140
  label
139
141
  end.to_sentence
@@ -169,7 +171,7 @@ module Blacklight::CatalogHelperBehavior
169
171
  constraints += search_state.filters.collect { |filter| render_search_to_page_title_filter(filter.key, filter.values) }
170
172
  end
171
173
 
172
- constraints.join(' / ')
174
+ constraints.join(t('blacklight.search.page_title.joiner'))
173
175
  end
174
176
 
175
177
  ##
@@ -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,17 +7,12 @@ module Blacklight::FacetsHelperBehavior
7
7
  facet_config.presenter.new(facet_config, display_facet, self)
8
8
  end
9
9
 
10
- private
11
-
12
- def facet_value_for_facet_item item
13
- if item.respond_to? :value
14
- item.value
15
- else
16
- item
17
- end
18
- end
19
-
20
- def facet_item_presenter(facet_config, facet_item, facet_field)
21
- facet_config.item_presenter.new(facet_item, facet_config, self, facet_field)
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
22
17
  end
23
18
  end
@@ -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
@@ -1,12 +1,17 @@
1
1
  import CheckboxSubmit from 'blacklight-frontend/checkbox_submit'
2
2
 
3
3
  const BookmarkToggle = (e) => {
4
- if (e.target.matches('[data-checkboxsubmit-target="checkbox"]')) {
5
- const form = e.target.closest('form')
4
+ const elementType = e.target.getAttribute('data-checkboxsubmit-target');
5
+ if (elementType == 'checkbox' || elementType == 'label') {
6
+ const form = e.target.closest('form');
6
7
  if (form) new CheckboxSubmit(form).clicked(e);
8
+ if (e.code == 'Space') e.preventDefault();
7
9
  }
8
10
  };
9
11
 
10
12
  document.addEventListener('click', BookmarkToggle);
13
+ document.addEventListener('keydown', function (e) {
14
+ if (e.key === 'Enter' || e.code == 'Space') { BookmarkToggle(e); } }
15
+ );
11
16
 
12
17
  export default BookmarkToggle