blacklight 7.16.0 → 7.17.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +4 -0
  3. data/VERSION +1 -1
  4. data/app/components/blacklight/advanced_search_form_component.html.erb +9 -3
  5. data/app/components/blacklight/advanced_search_form_component.rb +48 -35
  6. data/app/components/blacklight/constraints_component.html.erb +19 -3
  7. data/app/components/blacklight/constraints_component.rb +5 -1
  8. data/app/components/blacklight/content_areas_shim.rb +12 -0
  9. data/app/components/blacklight/document/action_component.rb +4 -0
  10. data/app/components/blacklight/document/actions_component.html.erb +3 -5
  11. data/app/components/blacklight/document/actions_component.rb +14 -1
  12. data/app/components/blacklight/document_component.html.erb +4 -7
  13. data/app/components/blacklight/document_component.rb +73 -73
  14. data/app/components/blacklight/document_metadata_component.html.erb +2 -2
  15. data/app/components/blacklight/document_metadata_component.rb +13 -2
  16. data/app/components/blacklight/document_title_component.html.erb +17 -0
  17. data/app/components/blacklight/document_title_component.rb +59 -0
  18. data/app/components/blacklight/facet_field_checkboxes_component.html.erb +2 -2
  19. data/app/components/blacklight/facet_field_component.rb +4 -1
  20. data/app/components/blacklight/facet_field_list_component.html.erb +2 -2
  21. data/app/components/blacklight/facet_field_no_layout_component.rb +4 -1
  22. data/app/components/blacklight/metadata_field_component.html.erb +2 -2
  23. data/app/components/blacklight/metadata_field_layout_component.html.erb +3 -1
  24. data/app/components/blacklight/metadata_field_layout_component.rb +26 -1
  25. data/app/components/blacklight/response/view_type_button_component.html.erb +4 -0
  26. data/app/components/blacklight/response/view_type_button_component.rb +36 -0
  27. data/app/components/blacklight/response/view_type_component.html.erb +2 -5
  28. data/app/components/blacklight/response/view_type_component.rb +9 -13
  29. data/app/components/blacklight/search_bar_component.rb +4 -1
  30. data/app/components/blacklight/system/dropdown_component.html.erb +4 -7
  31. data/app/components/blacklight/system/dropdown_component.rb +24 -0
  32. data/app/components/blacklight/system/flash_message_component.html.erb +1 -1
  33. data/app/components/blacklight/system/flash_message_component.rb +7 -1
  34. data/app/components/blacklight/system/modal_component.rb +7 -1
  35. data/app/views/catalog/_citation.html.erb +1 -1
  36. data/app/views/catalog/_document.html.erb +2 -2
  37. data/app/views/catalog/_facet_layout.html.erb +2 -2
  38. data/app/views/catalog/_show_main_content.html.erb +3 -3
  39. data/app/views/catalog/email.html.erb +2 -2
  40. data/app/views/catalog/email_success.html.erb +1 -1
  41. data/app/views/catalog/facet.html.erb +3 -3
  42. data/app/views/catalog/sms.html.erb +2 -2
  43. data/app/views/catalog/sms_success.html.erb +1 -1
  44. data/blacklight.gemspec +1 -1
  45. data/config/locales/blacklight.de.yml +2 -2
  46. data/lib/blacklight/engine.rb +3 -1
  47. data/lib/blacklight/solr/facet_paginator.rb +2 -0
  48. data/lib/blacklight/solr/request.rb +31 -0
  49. data/lib/blacklight/solr/response.rb +2 -16
  50. data/lib/blacklight/solr/response/facets.rb +76 -22
  51. data/lib/blacklight/solr/response/params.rb +104 -0
  52. data/lib/blacklight/solr/search_builder_behavior.rb +49 -29
  53. data/lib/generators/blacklight/assets_generator.rb +6 -2
  54. data/lib/generators/blacklight/user_generator.rb +1 -1
  55. data/spec/components/blacklight/document_component_spec.rb +3 -3
  56. data/spec/models/blacklight/solr/facet_paginator_spec.rb +4 -0
  57. data/spec/models/blacklight/solr/request_spec.rb +62 -29
  58. data/spec/models/blacklight/solr/response/facets_spec.rb +109 -0
  59. data/spec/models/blacklight/solr/response_spec.rb +10 -0
  60. data/spec/models/blacklight/solr/search_builder_spec.rb +17 -0
  61. metadata +14 -8
@@ -1,5 +1,5 @@
1
1
  <dl class="document-metadata dl-invert row">
2
- <% @fields.each do |field| -%>
3
- <%= @view_context.render(field_component(field).new(field: field, show: @show)) %>
2
+ <% fields.each do |field| -%>
3
+ <%= field %>
4
4
  <% end -%>
5
5
  </dl>
@@ -2,16 +2,27 @@
2
2
 
3
3
  module Blacklight
4
4
  class DocumentMetadataComponent < ::ViewComponent::Base
5
+ renders_many :fields, (lambda do |component: nil, **kwargs|
6
+ (component || Blacklight::MetadataFieldComponent).new(**kwargs)
7
+ end)
5
8
  with_collection_parameter :fields
6
9
 
7
10
  # @param fields [Enumerable<Blacklight::FieldPresenter>] Document field presenters
8
- def initialize(fields:, show: false)
11
+ def initialize(fields: [], show: false)
9
12
  @fields = fields
10
13
  @show = show
11
14
  end
12
15
 
16
+ def before_render
17
+ return unless fields
18
+
19
+ @fields.each do |field|
20
+ field(component: field_component(field), field: field, show: @show)
21
+ end
22
+ end
23
+
13
24
  def render?
14
- @fields.any?
25
+ fields.present?
15
26
  end
16
27
 
17
28
  def field_component(field)
@@ -0,0 +1,17 @@
1
+ <header class="documentHeader row">
2
+ <%= content_tag @as, class: @classes do %>
3
+ <% before_title.each do |t| %>
4
+ <%= t %>
5
+ <% end %>
6
+
7
+ <%= counter -%><%= title -%>
8
+
9
+ <% after_title.each do |t| %>
10
+ <%= t %>
11
+ <% end %>
12
+ <% end %>
13
+
14
+ <% actions.each do |action| %>
15
+ <%= action %>
16
+ <% end %>
17
+ </header>
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Blacklight
4
+ class DocumentTitleComponent < ::ViewComponent::Base
5
+ renders_many :before_title
6
+ renders_many :after_title
7
+ renders_many :actions
8
+
9
+ # rubocop:disable Metrics/ParameterLists
10
+ def initialize(title = nil, document: nil, presenter: nil, as: :h3, counter: nil, classes: 'index_title document-title-heading col', link_to_document: true, document_component: nil)
11
+ raise ArgumentError, 'missing keyword: :document or :presenter' if presenter.nil? && document.nil?
12
+
13
+ @title = title
14
+ @document = document
15
+ @presenter = presenter
16
+ @as = as || :h3
17
+ @counter = counter
18
+ @classes = classes
19
+ @link_to_document = link_to_document
20
+ @document_component = document_component
21
+ end
22
+ # rubocop:enable Metrics/ParameterLists
23
+
24
+ # Content for the document title area; should be an inline element
25
+ def title
26
+ if @link_to_document
27
+ @view_context.link_to_document presenter.document, @title.presence || content.presence, counter: @counter, itemprop: 'name'
28
+ else
29
+ content_tag('span', @title.presence || content.presence || presenter.heading, itemprop: 'name')
30
+ end
31
+ end
32
+
33
+ # Content for the document actions area
34
+ def actions
35
+ if block_given?
36
+ @has_actions_slot = true
37
+ return super
38
+ end
39
+
40
+ (@has_actions_slot && get_slot(:actions)) ||
41
+ ([@document_component&.actions] if @document_component&.actions.present?) ||
42
+ [@view_context.render_index_doc_actions(presenter.document, wrapping_class: 'index-document-functions col-sm-3 col-lg-2')]
43
+ end
44
+
45
+ def counter
46
+ return unless @counter
47
+
48
+ content_tag :span, class: 'document-counter' do
49
+ t('blacklight.search.documents.counter', counter: @counter)
50
+ end
51
+ end
52
+
53
+ private
54
+
55
+ def presenter
56
+ @presenter ||= @view_context.document_presenter(@document)
57
+ end
58
+ end
59
+ end
@@ -1,9 +1,9 @@
1
1
  <%= render(@layout.new(facet_field: @facet_field)) do |component| %>
2
- <% component.with(:label) do %>
2
+ <% component.label do %>
3
3
  <%= @facet_field.label %>
4
4
  <% end %>
5
5
 
6
- <% component.with(:body) do %>
6
+ <% component.body do %>
7
7
  <ul class="facet-values list-unstyled blacklight-facet-checkboxes">
8
8
  <% presenters.each_with_index do |presenter, idx| -%>
9
9
  <li>
@@ -2,7 +2,10 @@
2
2
 
3
3
  module Blacklight
4
4
  class FacetFieldComponent < ::ViewComponent::Base
5
- with_content_areas :label, :body
5
+ include Blacklight::ContentAreasShim
6
+
7
+ renders_one :label
8
+ renders_one :body
6
9
 
7
10
  def initialize(facet_field:)
8
11
  @facet_field = facet_field
@@ -1,8 +1,8 @@
1
1
  <%= render(@layout.new(facet_field: @facet_field)) do |component| %>
2
- <% component.with(:label) do %>
2
+ <% component.label do %>
3
3
  <%= @facet_field.label %>
4
4
  <% end %>
5
- <% component.with(:body) do %>
5
+ <% component.body do %>
6
6
  <%= @view_context.render(Blacklight::FacetFieldInclusiveConstraintComponent.new(facet_field: @facet_field)) %>
7
7
  <ul class="facet-values list-unstyled">
8
8
  <%= render_facet_limit_list @facet_field.paginator, @facet_field.key %>
@@ -2,7 +2,10 @@
2
2
 
3
3
  module Blacklight
4
4
  class FacetFieldNoLayoutComponent < ::ViewComponent::Base
5
- with_content_areas :label, :body
5
+ include Blacklight::ContentAreasShim
6
+
7
+ renders_one :label
8
+ renders_one :body
6
9
 
7
10
  def initialize(**); end
8
11
 
@@ -1,8 +1,8 @@
1
1
  <%= render(@layout.new(field: @field)) do |component| %>
2
- <% component.with(:label) do %>
2
+ <% component.label do %>
3
3
  <%= label %>
4
4
  <% end %>
5
- <% component.with(:value) do %>
5
+ <% component.value do %>
6
6
  <%= @field.render %>
7
7
  <% end %>
8
8
  <% end %>
@@ -1,2 +1,4 @@
1
1
  <dt class="blacklight-<%= @key %> <%= @label_class %>"><%= label %></dt>
2
- <dd class="blacklight-<%= @key %> <%= @value_class %>"><%= value %></dd>
2
+ <% values.each do |v| %>
3
+ <%= v %>
4
+ <% end %>
@@ -2,8 +2,17 @@
2
2
 
3
3
  module Blacklight
4
4
  class MetadataFieldLayoutComponent < ::ViewComponent::Base
5
+ include Blacklight::ContentAreasShim
6
+
5
7
  with_collection_parameter :field
6
- with_content_areas :label, :value
8
+ renders_one :label
9
+ renders_many :values, (lambda do |value: nil, &block|
10
+ if block
11
+ content_tag :dd, class: "#{@value_class} blacklight-#{@key}", &block
12
+ else
13
+ content_tag :dd, value, class: "#{@value_class} blacklight-#{@key}"
14
+ end
15
+ end)
7
16
 
8
17
  # @param field [Blacklight::FieldPresenter]
9
18
  def initialize(field:, label_class: 'col-md-3', value_class: 'col-md-9')
@@ -12,5 +21,21 @@ module Blacklight
12
21
  @label_class = label_class
13
22
  @value_class = value_class
14
23
  end
24
+
25
+ def value(*args, **kwargs, &block)
26
+ return set_slot(:values, *args, **kwargs, &block) if block_given?
27
+
28
+ Deprecation.warn('The `value` content area is deprecated; render from the values slot instead')
29
+
30
+ values.first
31
+ end
32
+
33
+ def with(slot_name, *args, **kwargs, &block)
34
+ if slot_name == :value
35
+ super(:values, *args, **kwargs, &block)
36
+ else
37
+ super
38
+ end
39
+ end
15
40
  end
16
41
  end
@@ -0,0 +1,4 @@
1
+ <%= link_to url, title: label, class: "#{Array(@classes).join(' ')} view-type-#{ @key.to_s.parameterize } #{"active" if selected?}" do %>
2
+ <%= icon %>
3
+ <span class="caption"><%= label %></span>
4
+ <% end %>
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Blacklight
4
+ module Response
5
+ # Render spellcheck results for a search query
6
+ class ViewTypeButtonComponent < ViewComponent::Base
7
+ with_collection_parameter :view
8
+ # @param [Blacklight::Configuration::View] view
9
+ def initialize(view:, key: nil, selected: false, search_state: nil, classes: 'btn btn-outline-secondary btn-icon')
10
+ @view = view
11
+ @key = key || view.key
12
+ @selected = selected
13
+ @classes = classes
14
+ @search_state = search_state
15
+ end
16
+
17
+ def icon
18
+ @view_context.render_view_type_group_icon(@view)
19
+ end
20
+
21
+ def label
22
+ Deprecation.silence(Blacklight::ConfigurationHelperBehavior) do
23
+ @view_context.view_label(@view)
24
+ end
25
+ end
26
+
27
+ def url
28
+ @view_context.url_for(@search_state.to_h.merge(view: @key))
29
+ end
30
+
31
+ def selected?
32
+ @selected
33
+ end
34
+ end
35
+ end
36
+ end
@@ -1,11 +1,8 @@
1
1
  <div class="view-type">
2
2
  <span class="sr-only"><%= t('blacklight.search.view_title') %></span>
3
3
  <div class="view-type-group btn-group">
4
- <% @views.each do |view, config| %>
5
- <%= link_to url(view), title: label(view), class: "btn btn-outline-secondary btn-icon view-type-#{ view.to_s.parameterize } #{"active" if @selected == view}" do %>
6
- <%= icon(view) %>
7
- <span class="caption"><%= label(view) %></span>
8
- <% end %>
4
+ <% views.each do |view| %>
5
+ <%= view %>
9
6
  <% end %>
10
7
  </div>
11
8
  </div>
@@ -4,6 +4,8 @@ module Blacklight
4
4
  module Response
5
5
  # Render spellcheck results for a search query
6
6
  class ViewTypeComponent < ViewComponent::Base
7
+ renders_many :views, 'Blacklight::Response::ViewTypeButtonComponent'
8
+
7
9
  # @param [Blacklight::Response] response
8
10
  def initialize(response:, views: {}, search_state:, selected: nil)
9
11
  @response = response
@@ -12,25 +14,19 @@ module Blacklight
12
14
  @selected = selected
13
15
  end
14
16
 
15
- def render?
16
- Deprecation.silence(Blacklight::ConfigurationHelperBehavior) do
17
- @view_context.has_alternative_views?
18
- end
19
- end
17
+ def before_render
18
+ return if views.any?
20
19
 
21
- def icon(view)
22
- @view_context.render_view_type_group_icon(view)
20
+ @views.each do |key, config|
21
+ view(key: key, view: config, selected: @selected == key, search_state: @search_state)
22
+ end
23
23
  end
24
24
 
25
- def label(view)
25
+ def render?
26
26
  Deprecation.silence(Blacklight::ConfigurationHelperBehavior) do
27
- @view_context.view_label(view)
27
+ @view_context.has_alternative_views?
28
28
  end
29
29
  end
30
-
31
- def url(view)
32
- @view_context.url_for(@search_state.to_h.merge(view: view))
33
- end
34
30
  end
35
31
  end
36
32
  end
@@ -2,7 +2,10 @@
2
2
 
3
3
  module Blacklight
4
4
  class SearchBarComponent < ::ViewComponent::Base
5
- with_content_areas :append, :prepend
5
+ include Blacklight::ContentAreasShim
6
+
7
+ renders_one :append
8
+ renders_one :prepend
6
9
 
7
10
  # rubocop:disable Metrics/ParameterLists
8
11
  def initialize(
@@ -1,12 +1,9 @@
1
1
  <%= content_tag :div, id: @id, class: @classes.join(' ') do %>
2
- <button type="button" class="btn btn-outline-secondary dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
3
- <%= t(:button_label_html, default: :label_html, scope: "blacklight.search.#{@param}", @interpolation => label_for_value(@selected)) %> <span class="caret"></span>
4
- </button>
2
+ <%= button %>
5
3
 
6
4
  <div class="dropdown-menu" role="menu">
7
- <%- @choices.each do |option| %>
8
- <% text, value = option_text_and_value(option) %>
9
- <%= link_to(text, @view_context.url_for(@search_state.params_for_search(@param => value)), class: 'dropdown-item', role: 'menuitem') %>
10
- <%- end -%>
5
+ <% options.each do |option| %>
6
+ <%= option %>
7
+ <% end %>
11
8
  </div>
12
9
  <% end %>
@@ -3,6 +3,15 @@
3
3
  module Blacklight
4
4
  module System
5
5
  class DropdownComponent < ViewComponent::Base
6
+ renders_one :button, (lambda do |classes:, label:|
7
+ button_tag class: classes, aria: { expanded: false }, data: { toggle: 'dropdown' } do
8
+ safe_join([label, content_tag(:span, '', class: 'caret')])
9
+ end
10
+ end)
11
+ renders_many :options, (lambda do |text:, url:, selected: false|
12
+ link_to(text, url, class: "dropdown-item #{'active' if selected}", role: 'menuitem', aria: { current: ('page' if selected) })
13
+ end)
14
+
6
15
  # rubocop:disable Metrics/ParameterLists
7
16
  def initialize(param:, choices:, search_state:, id: nil, classes: [], default: nil, selected: nil, interpolation: :field)
8
17
  @param = param
@@ -15,6 +24,21 @@ module Blacklight
15
24
  end
16
25
  # rubocop:enable Metrics/ParameterLists
17
26
 
27
+ def button_label
28
+ t(:button_label_html, default: :label_html, scope: "blacklight.search.#{@param}", @interpolation => label_for_value(@selected))
29
+ end
30
+
31
+ def before_render
32
+ button(classes: 'btn btn-outline-secondary dropdown-toggle', label: button_label) unless button
33
+
34
+ return if options.any?
35
+
36
+ options(@choices.map do |option|
37
+ text, value = option_text_and_value(option)
38
+ { text: text, url: @view_context.url_for(@search_state.params_for_search(@param => value)), selected: @selected == value }
39
+ end)
40
+ end
41
+
18
42
  def render?
19
43
  @choices.many?
20
44
  end
@@ -1,4 +1,4 @@
1
1
  <div class="alert <%= @classes %>">
2
- <%= @message %>
2
+ <%= message %>
3
3
  <a class="close" data-dismiss="alert" href="#">&times;</a>
4
4
  </div>
@@ -3,13 +3,19 @@
3
3
  module Blacklight
4
4
  module System
5
5
  class FlashMessageComponent < ViewComponent::Base
6
+ renders_one :message
7
+
6
8
  with_collection_parameter :message
7
9
 
8
- def initialize(message:, type:)
10
+ def initialize(message: nil, type:)
9
11
  @message = message
10
12
  @classes = alert_class(type)
11
13
  end
12
14
 
15
+ def before_render
16
+ message { @message } if @message
17
+ end
18
+
13
19
  def alert_class(type)
14
20
  case type.to_s
15
21
  when 'success' then "alert-success"
@@ -3,7 +3,13 @@
3
3
  module Blacklight
4
4
  module System
5
5
  class ModalComponent < ViewComponent::Base
6
- with_content_areas :prefix, :header, :title, :body, :footer
6
+ include Blacklight::ContentAreasShim
7
+
8
+ renders_one :prefix
9
+ renders_one :header
10
+ renders_one :title
11
+ renders_one :body
12
+ renders_one :footer
7
13
  end
8
14
  end
9
15
  end