blacklight 8.3.0 → 8.5.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 (142) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +10 -6
  3. data/.rubocop.yml +3 -0
  4. data/.rubocop_todo.yml +22 -55
  5. data/Gemfile +2 -10
  6. data/README.md +2 -2
  7. data/VERSION +1 -1
  8. data/app/assets/javascripts/blacklight/blacklight.esm.js +13 -7
  9. data/app/assets/javascripts/blacklight/blacklight.esm.js.map +1 -1
  10. data/app/assets/javascripts/blacklight/blacklight.js +13 -7
  11. data/app/assets/javascripts/blacklight/blacklight.js.map +1 -1
  12. data/app/assets/stylesheets/blacklight/_balanced_list.scss +1 -1
  13. data/app/assets/stylesheets/blacklight/_bookmark.scss +30 -0
  14. data/app/assets/stylesheets/blacklight/_bootstrap_overrides.scss +0 -4
  15. data/app/assets/stylesheets/blacklight/_constraints.scss +15 -9
  16. data/app/assets/stylesheets/blacklight/_controls.scss +0 -1
  17. data/app/assets/stylesheets/blacklight/_facets.scss +33 -37
  18. data/app/assets/stylesheets/blacklight/_header.scss +2 -35
  19. data/app/assets/stylesheets/blacklight/_icons.scss +3 -2
  20. data/app/assets/stylesheets/blacklight/_layout.scss +3 -0
  21. data/app/assets/stylesheets/blacklight/_mixins.scss +4 -4
  22. data/app/assets/stylesheets/blacklight/_search_form.scss +3 -8
  23. data/app/assets/stylesheets/blacklight/_search_history.scss +5 -5
  24. data/app/assets/stylesheets/blacklight/_search_results.scss +5 -2
  25. data/app/assets/stylesheets/blacklight/blacklight_defaults.scss +16 -10
  26. data/app/components/blacklight/advanced_search_form_component.html.erb +1 -1
  27. data/app/components/blacklight/advanced_search_form_component.rb +6 -0
  28. data/app/components/blacklight/constraint_layout_component.html.erb +2 -9
  29. data/app/components/blacklight/constraint_layout_component.rb +8 -0
  30. data/app/components/blacklight/constraints_component.rb +3 -3
  31. data/app/components/blacklight/document/action_component.rb +2 -1
  32. data/app/components/blacklight/document/bookmark_component.html.erb +2 -1
  33. data/app/components/blacklight/document/bookmark_component.rb +6 -0
  34. data/app/components/blacklight/document/page_header_component.html.erb +7 -0
  35. data/app/components/blacklight/document/page_header_component.rb +85 -0
  36. data/app/components/blacklight/document_component.rb +1 -1
  37. data/app/components/blacklight/facet_component.rb +1 -1
  38. data/app/components/blacklight/facet_field_checkboxes_component.html.erb +1 -1
  39. data/app/components/blacklight/facet_field_checkboxes_component.rb +1 -1
  40. data/app/components/blacklight/facet_field_inclusive_constraint_component.html.erb +1 -1
  41. data/app/components/blacklight/facet_field_list_component.html.erb +1 -1
  42. data/app/components/blacklight/facet_item_component.rb +1 -1
  43. data/app/components/blacklight/icons/bookmark_icon_component.rb +17 -0
  44. data/app/components/blacklight/icons/icon_component.rb +9 -4
  45. data/app/components/blacklight/icons/remove_component.rb +16 -0
  46. data/app/components/blacklight/metadata_field_component.html.erb +1 -1
  47. data/app/components/blacklight/metadata_field_component.rb +5 -0
  48. data/app/components/blacklight/response/facet_group_component.rb +1 -1
  49. data/app/components/blacklight/response/pagination_component.html.erb +1 -1
  50. data/app/components/blacklight/response/sort_component.html.erb +1 -6
  51. data/app/components/blacklight/response/sort_component.rb +15 -0
  52. data/app/components/blacklight/search/per_page_component.html.erb +2 -0
  53. data/app/components/blacklight/search/per_page_component.rb +50 -0
  54. data/app/components/blacklight/search_bar_component.html.erb +1 -1
  55. data/app/components/blacklight/search_context/server_item_pagination_component.html.erb +5 -4
  56. data/app/components/blacklight/search_context/server_item_pagination_component.rb +1 -1
  57. data/app/components/blacklight/skip_link_component.html.erb +7 -0
  58. data/app/components/blacklight/skip_link_component.rb +17 -0
  59. data/app/components/blacklight/system/dropdown_button_component.rb +18 -0
  60. data/app/components/blacklight/system/dropdown_component.rb +3 -6
  61. data/app/components/blacklight/system/flash_message_component.html.erb +1 -1
  62. data/app/components/blacklight/top_navbar_component.html.erb +2 -2
  63. data/app/components/blacklight/top_navbar_component.rb +4 -0
  64. data/app/helpers/blacklight/catalog_helper_behavior.rb +2 -0
  65. data/app/helpers/blacklight/component_helper_behavior.rb +4 -4
  66. data/app/helpers/blacklight/configuration_helper_behavior.rb +2 -0
  67. data/app/helpers/blacklight/document_helper_behavior.rb +14 -0
  68. data/app/javascript/blacklight/checkbox_submit.js +7 -1
  69. data/app/javascript/blacklight/core.js +5 -5
  70. data/app/models/concerns/blacklight/document/semantic_fields.rb +1 -1
  71. data/app/presenters/blacklight/facet_checkbox_item_presenter.rb +11 -0
  72. data/app/presenters/blacklight/facet_field_presenter.rb +9 -1
  73. data/app/services/blacklight/search_service.rb +9 -1
  74. data/app/views/catalog/_per_page_widget.html.erb +1 -10
  75. data/app/views/catalog/_search_results.html.erb +1 -1
  76. data/app/views/catalog/_show_main_content.html.erb +1 -1
  77. data/app/views/catalog/_show_sidebar.html.erb +1 -0
  78. data/app/views/catalog/show.html.erb +3 -3
  79. data/app/views/catalog/suggest.html.erb +1 -1
  80. data/app/views/kaminari/blacklight/_page.html.erb +14 -8
  81. data/app/views/kaminari/blacklight/_paginator.html.erb +2 -1
  82. data/app/views/layouts/blacklight/base.html.erb +3 -5
  83. data/blacklight.gemspec +6 -2
  84. data/{docker-compose.yml → compose.yaml} +1 -1
  85. data/config/locales/blacklight.ar.yml +3 -0
  86. data/config/locales/blacklight.de.yml +3 -0
  87. data/config/locales/blacklight.en.yml +216 -229
  88. data/config/locales/blacklight.es.yml +3 -0
  89. data/config/locales/blacklight.fr.yml +3 -0
  90. data/config/locales/blacklight.hu.yml +3 -0
  91. data/config/locales/blacklight.it.yml +3 -0
  92. data/config/locales/blacklight.nl.yml +3 -0
  93. data/config/locales/blacklight.pt-BR.yml +3 -0
  94. data/config/locales/blacklight.sq.yml +3 -0
  95. data/config/locales/blacklight.zh.yml +3 -0
  96. data/lib/blacklight/abstract_repository.rb +6 -0
  97. data/lib/blacklight/component.rb +10 -47
  98. data/lib/blacklight/configuration.rb +32 -19
  99. data/lib/blacklight/engine.rb +6 -0
  100. data/lib/blacklight/parameters.rb +1 -1
  101. data/lib/blacklight/solr/repository.rb +11 -4
  102. data/lib/blacklight/solr/response/params.rb +1 -1
  103. data/lib/blacklight/solr/response.rb +0 -12
  104. data/lib/blacklight/solr/search_builder_behavior.rb +1 -1
  105. data/lib/blacklight/solr.rb +0 -6
  106. data/lib/blacklight.rb +4 -14
  107. data/lib/generators/blacklight/assets/propshaft_generator.rb +2 -2
  108. data/lib/generators/blacklight/models_generator.rb +1 -1
  109. data/lib/generators/blacklight/user_generator.rb +2 -0
  110. data/package.json +3 -2
  111. data/rollup.config.js +6 -12
  112. data/spec/components/blacklight/document/action_component_spec.rb +1 -1
  113. data/spec/components/blacklight/document/page_header_component_spec.rb +92 -0
  114. data/spec/components/blacklight/document_component_spec.rb +20 -0
  115. data/spec/components/blacklight/icons/icon_component_spec.rb +42 -0
  116. data/spec/components/blacklight/search_context/server_item_pagination_component_spec.rb +13 -2
  117. data/spec/controllers/blacklight/catalog_spec.rb +1 -1
  118. data/spec/controllers/catalog_controller_spec.rb +5 -5
  119. data/spec/features/advanced_search_spec.rb +16 -2
  120. data/spec/features/bookmarks_spec.rb +15 -0
  121. data/spec/features/search_context_spec.rb +2 -1
  122. data/spec/helpers/blacklight/facets_helper_behavior_spec.rb +2 -2
  123. data/spec/lib/blacklight/component_spec.rb +32 -27
  124. data/spec/lib/blacklight/nested_open_struct_with_hash_access_spec.rb +1 -1
  125. data/spec/lib/blacklight/open_struct_with_hash_access_spec.rb +1 -1
  126. data/spec/models/blacklight/configuration_spec.rb +12 -12
  127. data/spec/models/blacklight/solr/document_spec.rb +2 -2
  128. data/spec/models/blacklight/solr/repository_spec.rb +31 -13
  129. data/spec/models/blacklight/solr/response/facets_spec.rb +2 -2
  130. data/spec/models/blacklight/solr/response/group_spec.rb +1 -1
  131. data/spec/models/blacklight/solr/response_spec.rb +2 -2
  132. data/spec/models/blacklight/solr/search_builder_behavior_spec.rb +1 -1
  133. data/spec/models/bookmark_spec.rb +1 -1
  134. data/spec/presenters/blacklight/document_presenter_spec.rb +2 -2
  135. data/spec/presenters/blacklight/facet_checkbox_item_presenter_spec.rb +42 -0
  136. data/spec/presenters/blacklight/facet_field_presenter_spec.rb +14 -0
  137. data/spec/requests/load_suggestions_spec.rb +5 -5
  138. data/spec/services/blacklight/search_service_spec.rb +2 -2
  139. data/spec/spec_helper.rb +5 -2
  140. data/spec/test_app_templates/lib/generators/test_app_generator.rb +1 -1
  141. data/tasks/blacklight.rake +6 -6
  142. metadata +86 -8
@@ -10,6 +10,14 @@ module Blacklight
10
10
  @search_state = search_state
11
11
  end
12
12
 
13
+ def remove_aria_label
14
+ if @label.blank?
15
+ t('blacklight.search.filters.remove.value', value: @value)
16
+ else
17
+ t('blacklight.search.filters.remove.label_value', label: @label, value: @value)
18
+ end
19
+ end
20
+
13
21
  def render?
14
22
  @value.present?
15
23
  end
@@ -41,7 +41,7 @@ module Blacklight
41
41
 
42
42
  def query_constraints
43
43
  if @search_state.query_param.present?
44
- helpers.render(
44
+ render(
45
45
  @query_constraint_component.new(
46
46
  search_state: @search_state,
47
47
  value: @search_state.query_param,
@@ -53,7 +53,7 @@ module Blacklight
53
53
  )
54
54
  else
55
55
  ''.html_safe
56
- end + helpers.render(@facet_constraint_component.with_collection(clause_presenters.to_a, **@facet_constraint_component_options))
56
+ end + render(@facet_constraint_component.with_collection(clause_presenters.to_a, **@facet_constraint_component_options))
57
57
  end
58
58
 
59
59
  def remove_path
@@ -61,7 +61,7 @@ module Blacklight
61
61
  end
62
62
 
63
63
  def facet_constraints
64
- helpers.render(@facet_constraint_component.with_collection(facet_item_presenters.to_a, **@facet_constraint_component_options))
64
+ render(@facet_constraint_component.with_collection(facet_item_presenters.to_a, **@facet_constraint_component_options))
65
65
  end
66
66
 
67
67
  def render?
@@ -35,7 +35,8 @@ module Blacklight
35
35
  end
36
36
 
37
37
  def render_partial
38
- helpers.render(partial: @action.partial || @action.name.to_s, locals: { document: @document, document_action_config: @action }.merge(@options))
38
+ render(partial: @action.partial || @action.name.to_s,
39
+ locals: { document: @document, document_action_config: @action }.merge(@options))
39
40
  end
40
41
 
41
42
  def label
@@ -10,7 +10,8 @@
10
10
  }) do %>
11
11
  <div class="checkbox toggle-bookmark">
12
12
  <label class="toggle-bookmark" data-checkboxsubmit-target="label">
13
- <input type="checkbox" class="toggle-bookmark" data-checkboxsubmit-target="checkbox" <%= 'checked="checked"' if bookmarked? %>>
13
+ <input type="checkbox" class="toggle-bookmark <%= bookmark_icon ? 'd-none' : '' %>" data-checkboxsubmit-target="checkbox" <%= 'checked="checked"' if bookmarked? %>>
14
+ <%= bookmark_icon %>
14
15
  <span data-checkboxsubmit-target="span"><%= bookmarked? ? t('blacklight.search.bookmarks.present') : t('blacklight.search.bookmarks.absent') %></span>
15
16
  </label>
16
17
  </div>
@@ -21,6 +21,12 @@ module Blacklight
21
21
  helpers.bookmarked? @document
22
22
  end
23
23
 
24
+ def bookmark_icon
25
+ return unless helpers.blacklight_config.bookmark_icon_component
26
+
27
+ render helpers.blacklight_config.bookmark_icon_component.new(name: 'bookmark')
28
+ end
29
+
24
30
  def bookmark_path
25
31
  @bookmark_path || helpers.bookmark_path(@document)
26
32
  end
@@ -0,0 +1,7 @@
1
+ <%= render applied_params_component %>
2
+ <div class="<%= header_container_classes %>">
3
+ <div class="<%= pagination_container_classes %>">
4
+ <%= render pagination_component %>
5
+ </div>
6
+ <%= render_header_tools %>
7
+ </div>
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Blacklight
4
+ module Document
5
+ # Render the start over and prev/next displays
6
+ class PageHeaderComponent < Blacklight::Component
7
+ attr_reader :document, :blacklight_config, :search_context, :search_session
8
+
9
+ delegate :blacklight_config, to: :helpers
10
+
11
+ def initialize(document:, search_context:, search_session:)
12
+ super
13
+ @search_context = search_context
14
+ @search_session = search_session
15
+ @document = document
16
+ end
17
+
18
+ def render?
19
+ search_context.present? || search_session.present? || has_header_tools?
20
+ end
21
+
22
+ def applied_params_component
23
+ return unless blacklight_config.track_search_session.applied_params_component
24
+
25
+ blacklight_config.track_search_session.applied_params_component.new
26
+ end
27
+
28
+ def pagination_component
29
+ return unless blacklight_config.track_search_session.item_pagination_component
30
+
31
+ blacklight_config.track_search_session.item_pagination_component.new(search_context: search_context, search_session: search_session, current_document: document)
32
+ end
33
+
34
+ def has_header_tools?
35
+ header_actions.any? || show_header_tools_component
36
+ end
37
+
38
+ def pagination_container_classes
39
+ has_header_tools? ? 'col-12 col-md-6 ms-auto' : ''
40
+ end
41
+
42
+ def header_container_classes
43
+ has_header_tools? ? 'row pagination-search-widgets pb-2' : 'pagination-search-widgets'
44
+ end
45
+
46
+ def header_actions
47
+ actions = helpers.filter_partials(blacklight_config.view_config(:show).header_actions, { document: document })
48
+ actions.map { |_k, v| v }
49
+ end
50
+
51
+ def show_header_tools_component
52
+ blacklight_config.view_config(:show).show_header_tools_component
53
+ end
54
+
55
+ def default_action_component_render
56
+ render Blacklight::Document::ActionsComponent.new(document: document,
57
+ tag: action_component_tag,
58
+ classes: classes,
59
+ link_classes: link_classes,
60
+ actions: header_actions,
61
+ url_opts: Blacklight::Parameters.sanitize(params.to_unsafe_h))
62
+ end
63
+
64
+ def action_component_tag
65
+ 'div'
66
+ end
67
+
68
+ def classes
69
+ 'd-inline-flex header-tools align-items-center col-12 col-md-6 ms-auto justify-content-md-end'
70
+ end
71
+
72
+ def link_classes
73
+ 'btn btn-outline-primary ms-2'
74
+ end
75
+
76
+ def render_header_tools
77
+ return unless has_header_tools?
78
+
79
+ return render show_header_tools_component.new(document: document) if show_header_tools_component
80
+
81
+ default_action_component_render
82
+ end
83
+ end
84
+ end
85
+ end
@@ -127,7 +127,7 @@ module Blacklight
127
127
  def before_render
128
128
  set_slot(:title, nil) unless title
129
129
  set_slot(:thumbnail, nil) unless thumbnail || show?
130
- set_slot(:metadata, nil, fields: presenter.field_presenters) unless metadata
130
+ set_slot(:metadata, nil, fields: presenter.field_presenters, show: @show) unless metadata
131
131
  set_slot(:embed, nil) unless embed
132
132
  if view_partials.present?
133
133
  view_partials.each do |view_partial|
@@ -51,7 +51,7 @@ module Blacklight
51
51
  end
52
52
 
53
53
  def render_partial
54
- helpers.render(@field_config.partial, locals: { field_name: @field_config.field, facet_field: @field_config, display_facet: @display_facet }.merge(@component_args))
54
+ render(@field_config.partial, locals: { field_name: @field_config.field, facet_field: @field_config, display_facet: @display_facet }.merge(@component_args))
55
55
  end
56
56
  end
57
57
  end
@@ -16,7 +16,7 @@
16
16
  <span class="facet-label"><%= presenter.label %></span>
17
17
  <span class="facet-count"><%= t('blacklight.search.facets.count', number: number_with_delimiter(presenter.hits)) %></span>
18
18
  <% end %>
19
- <span>
19
+ </span>
20
20
  </li>
21
21
  <% end -%>
22
22
  </ul>
@@ -17,7 +17,7 @@ module Blacklight
17
17
  return to_enum(:presenters) unless block_given?
18
18
 
19
19
  @facet_field.paginator.items.each do |item|
20
- yield @facet_field.facet_field.item_presenter.new(item, @facet_field.facet_field, helpers, @facet_field.key, @facet_field.search_state)
20
+ yield Blacklight::FacetCheckboxItemPresenter.new(item, @facet_field.facet_field, helpers, @facet_field.key, @facet_field.search_state)
21
21
  end
22
22
  end
23
23
  end
@@ -1,6 +1,6 @@
1
1
  <div class="inclusive_or card card-body bg-light mb-3">
2
2
  <h5><%= t('blacklight.advanced_search.any_of') %></h5>
3
3
  <ul class="list-unstyled facet-values">
4
- <%= helpers.render(Blacklight::FacetItemComponent.with_collection(presenters.to_a)) %>
4
+ <%= render(Blacklight::FacetItemComponent.with_collection(presenters.to_a)) %>
5
5
  </ul>
6
6
  </div>
@@ -3,7 +3,7 @@
3
3
  <%= @facet_field.label %>
4
4
  <% end %>
5
5
  <% component.with_body do %>
6
- <%= helpers.render(Blacklight::FacetFieldInclusiveConstraintComponent.new(facet_field: @facet_field)) %>
6
+ <%= render(Blacklight::FacetFieldInclusiveConstraintComponent.new(facet_field: @facet_field)) %>
7
7
  <ul class="facet-values list-unstyled">
8
8
  <%= render facet_items %>
9
9
  </ul>
@@ -54,7 +54,7 @@ module Blacklight
54
54
  tag.span(label, class: "selected") +
55
55
  # remove link
56
56
  link_to(href, class: "remove", rel: "nofollow") do
57
- tag.span('✖', class: "remove-icon", aria: { hidden: true }) +
57
+ render(Blacklight::Icons::RemoveComponent.new) +
58
58
  tag.span(helpers.t(:'blacklight.search.facets.selected.remove'), class: 'sr-only visually-hidden')
59
59
  end
60
60
  end + render_facet_count(classes: ["selected"])
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Blacklight
4
+ module Icons
5
+ class BookmarkIconComponent < Blacklight::Icons::IconComponent
6
+ self.svg = <<~SVG
7
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-bookmark-check-fill bookmark-checked" viewBox="0 0 16 16">
8
+ <path fill-rule="evenodd" d="M2 15.5V2a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v13.5a.5.5 0 0 1-.74.439L8 13.069l-5.26 2.87A.5.5 0 0 1 2 15.5m8.854-9.646a.5.5 0 0 0-.708-.708L7.5 7.793 6.354 6.646a.5.5 0 1 0-.708.708l1.5 1.5a.5.5 0 0 0 .708 0z"/>
9
+ </svg>
10
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-bookmark-plus bookmark-unchecked" viewBox="0 0 16 16">
11
+ <path d="M2 2a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v13.5a.5.5 0 0 1-.777.416L8 13.101l-5.223 2.815A.5.5 0 0 1 2 15.5zm2-1a1 1 0 0 0-1 1v12.566l4.723-2.482a.5.5 0 0 1 .554 0L13 14.566V2a1 1 0 0 0-1-1z"/>
12
+ <path d="M8 4a.5.5 0 0 1 .5.5V6H10a.5.5 0 0 1 0 1H8.5v1.5a.5.5 0 0 1-1 0V7H6a.5.5 0 0 1 0-1h1.5V4.5A.5.5 0 0 1 8 4"/>
13
+ </svg>
14
+ SVG
15
+ end
16
+ end
17
+ end
@@ -2,15 +2,16 @@
2
2
 
3
3
  module Blacklight
4
4
  module Icons
5
- # This is the list icon for the search button.
5
+ # This is the base class for icon components. You should extend this class for each icon.
6
+ #
6
7
  # You can override the default svg by setting:
7
- # Blacklight::Icons::ListComponent.svg = '<svg>your SVG here</svg>'
8
+ # Blacklight::Icons::MyIconComponent.svg = '<svg>your SVG here</svg>'
8
9
  class IconComponent < ::ViewComponent::Base
9
10
  # rubocop:disable Metrics/ParameterLists
10
11
  def initialize(svg: nil, tag: :span, name: nil, label: nil, aria_hidden: nil, classes: nil, **options)
11
12
  self.svg = svg if svg
12
- @classes = Array(classes) + ['blacklight-icons', "blacklight-icons-#{name}"]
13
13
  @name = name
14
+ @assigned_classes = Array(classes)
14
15
  @tag = tag
15
16
  @options = options.merge(aria: options.fetch(:aria, {}).reverse_merge(label: label, hidden: aria_hidden))
16
17
  end
@@ -18,12 +19,16 @@ module Blacklight
18
19
 
19
20
  def call
20
21
  tag.public_send(@tag, svg&.html_safe, # rubocop:disable Rails/OutputSafety
21
- class: @classes,
22
+ class: classes,
22
23
  **@options)
23
24
  end
24
25
 
25
26
  class_attribute :svg
26
27
 
28
+ def classes
29
+ @classes ||= @assigned_classes + ['blacklight-icons', "blacklight-icons-#{name}"]
30
+ end
31
+
27
32
  def name
28
33
  @name ||= self.class.name.demodulize.underscore.sub('_component', '')
29
34
  end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Blacklight
4
+ module Icons
5
+ # This is the remove (x) icon for the facets and constraints.
6
+ # You can override the default svg by setting:
7
+ # Blacklight::Icons::RemoveComponent.svg = '<svg>your SVG here</svg>'
8
+ class RemoveComponent < Blacklight::Icons::IconComponent
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"/>
12
+ </svg>
13
+ SVG
14
+ end
15
+ end
16
+ end
@@ -3,6 +3,6 @@
3
3
  <%= label %>
4
4
  <% end %>
5
5
  <% component.with_value do %>
6
- <%= @field.render %>
6
+ <%= render_field %>
7
7
  <% end %>
8
8
  <% end %>
@@ -26,6 +26,11 @@ module Blacklight
26
26
  @field.render_field?
27
27
  end
28
28
 
29
+ # Override this method in a subclass to change the way this value is rendered
30
+ def render_field
31
+ @field.render
32
+ end
33
+
29
34
  ##
30
35
  # Render the index field label for a document
31
36
  #
@@ -35,7 +35,7 @@ module Blacklight
35
35
  # @deprecated
36
36
  def default_body
37
37
  Blacklight.deprecation.warn('Rendering the Blacklight::FacetGroupComponent without a body slot is deprecated.')
38
- helpers.render(Blacklight::FacetComponent.with_collection(@fields, response: @response))
38
+ render(Blacklight::FacetComponent.with_collection(@fields, response: @response))
39
39
  end
40
40
 
41
41
  # @deprecated
@@ -1,3 +1,3 @@
1
- <%= content_tag :section, class: 'paginate-section', **html_attr do %>
1
+ <%= tag.nav class: 'paginate-section', **html_attr do %>
2
2
  <%= pagination %>
3
3
  <% end %>
@@ -1,6 +1 @@
1
- <%= helpers.render(Blacklight::System::DropdownComponent.new(
2
- param: @param,
3
- choices: @choices,
4
- id: @id,
5
- search_state: @search_state,
6
- selected: @selected)) %>
1
+ <%= dropdown %>
@@ -11,6 +11,21 @@ module Blacklight
11
11
  @classes = classes
12
12
  @selected = selected
13
13
  end
14
+
15
+ # You may override this method in a subclass if you want to use a different dropdown component
16
+ def dropdown_class
17
+ helpers.blacklight_config.view_config(:show).dropdown_component
18
+ end
19
+
20
+ def dropdown
21
+ render(dropdown_class.new(
22
+ param: @param,
23
+ choices: @choices,
24
+ id: @id,
25
+ search_state: @search_state,
26
+ selected: @selected
27
+ ))
28
+ end
14
29
  end
15
30
  end
16
31
  end
@@ -0,0 +1,2 @@
1
+ <span class="sr-only visually-hidden"><%= t('blacklight.search.per_page.title') %></span>
2
+ <%= dropdown %>
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Blacklight
4
+ module Search
5
+ class PerPageComponent < Blacklight::Component
6
+ def initialize(blacklight_config:, response:, search_state:)
7
+ @blacklight_config = blacklight_config
8
+ @response = response
9
+ @search_state = search_state
10
+ end
11
+
12
+ def render?
13
+ helpers.show_sort_and_per_page?
14
+ end
15
+
16
+ # You may override this method in a subclass if you want to use a different dropdown component
17
+ def dropdown_class
18
+ @blacklight_config.view_config(:show).dropdown_component
19
+ end
20
+
21
+ def dropdown
22
+ render(dropdown_class.new(
23
+ param: :per_page,
24
+ choices: per_page_options_for_select,
25
+ id: 'per_page-dropdown',
26
+ search_state: @search_state,
27
+ selected: current_per_page,
28
+ interpolation: :count
29
+ ))
30
+ end
31
+
32
+ #
33
+ # @return [Integer]
34
+ def current_per_page
35
+ (@response.rows if @response && @response.rows > 0) || # rubocop:disable Style/NumericPredicate
36
+ params.fetch(:per_page, @blacklight_config.default_per_page).to_i
37
+ end
38
+
39
+ ##
40
+ # The available options for results per page, in the style of #options_for_select
41
+ def per_page_options_for_select
42
+ return [] if @blacklight_config.per_page.blank?
43
+
44
+ @blacklight_config.per_page.map do |count|
45
+ [t(:'blacklight.search.per_page.label', count: count).html_safe, count]
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -24,7 +24,7 @@
24
24
  <% if autocomplete_path.present? %>
25
25
  <auto-complete src="<%= autocomplete_path %>" for="autocomplete-popup" class="search-autocomplete-wrapper">
26
26
  <%= f.search_field @query_param, value: @q, placeholder: scoped_t('search.placeholder'), class: "search-q q form-control rounded-#{search_fields.length > 1 ? '0' : 'left'}", autofocus: @autofocus, aria: { label: scoped_t('search.label'), autocomplete: 'list', controls: 'autocomplete-popup' } %>
27
- <ul id="autocomplete-popup" role="listbox" aria-label="<%= scoped_t('search.label') %>" hidden></ul>
27
+ <ul id="autocomplete-popup" class="dropdown-menu" role="listbox" aria-label="<%= scoped_t('search.label') %>" hidden></ul>
28
28
  </auto-complete>
29
29
  <% else %>
30
30
  <%= f.search_field @query_param, value: @q, placeholder: scoped_t('search.placeholder'), class: "search-q q form-control rounded-#{search_fields.length > 1 ? '0' : 'left'}", autofocus: @autofocus, aria: { label: scoped_t('search.label') } %>
@@ -1,10 +1,11 @@
1
- <div class='pagination-search-widgets'>
2
-
3
- <div class="page-links">
1
+ <div class="search-context page-links">
2
+ <% if total == 1 %>
3
+ <%= item_page_entry_info %>
4
+ <% else %>
4
5
  <%= link_to_previous_document %> |
5
6
 
6
7
  <%= item_page_entry_info %> |
7
8
 
8
9
  <%= link_to_next_document %>
9
- </div>
10
+ <% end %>
10
11
  </div>
@@ -12,7 +12,7 @@ module Blacklight
12
12
  end
13
13
 
14
14
  def render?
15
- @search_context.present? && (@search_context[:prev] || @search_context[:next]) && (@search_session['document_id'] == @current_document_id)
15
+ @search_context.present? && (@search_context[:prev] || @search_context[:next] || total.positive?) && (@search_session['document_id'] == @current_document_id)
16
16
  end
17
17
 
18
18
  ##
@@ -0,0 +1,7 @@
1
+ <nav id="skip-link" role="navigation" class="visually-hidden-focusable sr-only sr-only-focusable" aria-label="<%= t('blacklight.skip_links.label') %>">
2
+ <div class="container-xl">
3
+ <%= link_to_main %>
4
+ <%= link_to_search %>
5
+ <%= content %>
6
+ </div>
7
+ </nav>
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Blacklight
4
+ class SkipLinkComponent < Blacklight::Component
5
+ def link_to_search
6
+ link_to t('blacklight.skip_links.search_field'), '#search_field', class: link_classes
7
+ end
8
+
9
+ def link_to_main
10
+ link_to t('blacklight.skip_links.main_content'), '#main-container', class: link_classes
11
+ end
12
+
13
+ def link_classes
14
+ 'd-inline-flex p-2 m-1'
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Blacklight
4
+ module System
5
+ class DropdownButtonComponent < Blacklight::Component
6
+ def initialize(label:, classes: %w[btn btn-outline-secondary dropdown-toggle])
7
+ @classes = classes
8
+ @label = label
9
+ end
10
+
11
+ def call
12
+ button_tag class: @classes, aria: { expanded: false }, data: { toggle: 'dropdown', 'bs-toggle': 'dropdown' } do
13
+ safe_join([@label, content_tag(:span, '', class: 'caret')])
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -3,11 +3,8 @@
3
3
  module Blacklight
4
4
  module System
5
5
  class DropdownComponent < Blacklight::Component
6
- renders_one :button, (lambda do |classes:, label:|
7
- button_tag class: classes, aria: { expanded: false }, data: { toggle: 'dropdown', 'bs-toggle': 'dropdown' } do
8
- safe_join([label, content_tag(:span, '', class: 'caret')])
9
- end
10
- end)
6
+ renders_one :button, DropdownButtonComponent
7
+
11
8
  renders_many :options, (lambda do |text:, url:, selected: false|
12
9
  link_to(text, url, class: "dropdown-item #{'active' if selected}", role: 'menuitem', aria: { current: ('page' if selected) })
13
10
  end)
@@ -29,7 +26,7 @@ module Blacklight
29
26
  end
30
27
 
31
28
  def before_render
32
- with_button(classes: 'btn btn-outline-secondary dropdown-toggle', label: button_label) unless button
29
+ with_button(label: button_label) unless button
33
30
 
34
31
  return if options.any?
35
32
 
@@ -1,4 +1,4 @@
1
- <div class="alert <%= @classes %>">
1
+ <div class="alert alert-dismissible <%= @classes %>">
2
2
  <%= message %>
3
3
  <%= tag.button button_contents, type: "button", class: "btn-close",
4
4
  data: { dismiss: "alert", bs_dismiss: "alert" },
@@ -1,4 +1,4 @@
1
- <nav class="navbar navbar-expand-md navbar-dark bg-dark topbar" role="navigation">
1
+ <nav class="navbar navbar-expand-md navbar-dark bg-dark topbar" aria-label="<%= aria_label %>">
2
2
  <div class="<%= container_classes %>">
3
3
  <%= logo_link %>
4
4
  <button class="navbar-toggler navbar-toggler-right" 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">
@@ -9,4 +9,4 @@
9
9
  <%= render 'shared/user_util_links' %>
10
10
  </div>
11
11
  </div>
12
- </nav>
12
+ </nav>
@@ -10,6 +10,10 @@ module Blacklight
10
10
 
11
11
  delegate :application_name, :container_classes, to: :helpers
12
12
 
13
+ def aria_label
14
+ t('blacklight.top_navbar.aria.container_label')
15
+ end
16
+
13
17
  def logo_link(title: application_name)
14
18
  link_to title, blacklight_config.logo_link, class: 'mb-0 navbar-brand navbar-logo'
15
19
  end
@@ -105,10 +105,12 @@ module Blacklight::CatalogHelperBehavior
105
105
  ##
106
106
  # Look up the current per page value, or the default if none if set
107
107
  #
108
+ # @deprecated
108
109
  # @return [Integer]
109
110
  def current_per_page
110
111
  (@response.rows if @response && @response.rows > 0) || params.fetch(:per_page, blacklight_config.default_per_page).to_i
111
112
  end
113
+ Blacklight.deprecation.deprecate_methods(self, current_per_page: 'has moved to Blacklight::Search::PerPageComponent')
112
114
 
113
115
  ##
114
116
  # Should we display the sort and per page widget?
@@ -37,6 +37,10 @@ module Blacklight
37
37
  filter_partials(blacklight_config.view_config(:show).document_actions, { document: document }.merge(options)).map { |_k, v| v }
38
38
  end
39
39
 
40
+ def filter_partials(partials, options)
41
+ partials.select { |_, config| blacklight_configuration_context.evaluate_if_unless_configuration config, options }
42
+ end
43
+
40
44
  private
41
45
 
42
46
  def render_filtered_partials(partials, options = {})
@@ -52,9 +56,5 @@ module Blacklight
52
56
  end
53
57
  safe_join(content, "\n") unless block_given?
54
58
  end
55
-
56
- def filter_partials(partials, options)
57
- partials.select { |_, config| blacklight_configuration_context.evaluate_if_unless_configuration config, options }
58
- end
59
59
  end
60
60
  end
@@ -92,6 +92,7 @@ module Blacklight::ConfigurationHelperBehavior
92
92
  end
93
93
 
94
94
  ##
95
+ # @deprecated
95
96
  # The available options for results per page, in the style of #options_for_select
96
97
  def per_page_options_for_select
97
98
  return [] if blacklight_config.per_page.blank?
@@ -100,6 +101,7 @@ module Blacklight::ConfigurationHelperBehavior
100
101
  [t(:'blacklight.search.per_page.label', count: count).html_safe, count]
101
102
  end
102
103
  end
104
+ Blacklight.deprecation.deprecate_methods(self, per_page_options_for_select: 'has moved to Blacklight::Search::PerPageComponent')
103
105
 
104
106
  ##
105
107
  # Determine whether to render a field by evaluating :if and :unless conditions