blacklight 8.3.0 → 8.5.0

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