blacklight 8.1.0 → 8.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +8 -6
  3. data/.rubocop_todo.yml +20 -5
  4. data/VERSION +1 -1
  5. data/app/assets/javascripts/blacklight/blacklight.esm.js +41 -21
  6. data/app/assets/javascripts/blacklight/blacklight.esm.js.map +1 -1
  7. data/app/assets/javascripts/blacklight/blacklight.js +41 -21
  8. data/app/assets/javascripts/blacklight/blacklight.js.map +1 -1
  9. data/app/assets/stylesheets/blacklight/_mixins.scss +1 -1
  10. data/app/components/blacklight/advanced_search_form_component.html.erb +3 -3
  11. data/app/components/blacklight/advanced_search_form_component.rb +1 -1
  12. data/app/components/blacklight/document/bookmark_component.html.erb +1 -6
  13. data/app/components/blacklight/facet_field_component.html.erb +2 -1
  14. data/app/components/blacklight/icons/legacy_icon_component.rb +1 -1
  15. data/app/components/blacklight/response/facet_group_component.html.erb +0 -1
  16. data/app/components/blacklight/search/sidebar_component.html.erb +8 -6
  17. data/app/components/blacklight/search_bar_component.html.erb +36 -34
  18. data/app/components/blacklight/system/flash_message_component.html.erb +1 -1
  19. data/app/controllers/concerns/blacklight/token_based_user.rb +5 -19
  20. data/app/helpers/blacklight/url_helper_behavior.rb +3 -2
  21. data/app/javascript/blacklight/checkbox_submit.js +15 -10
  22. data/app/javascript/blacklight/modal.js +26 -12
  23. data/app/javascript/blacklight/search_context.js +1 -0
  24. data/app/values/blacklight/types.rb +14 -0
  25. data/app/views/catalog/_advanced_search_form.html.erb +1 -1
  26. data/app/views/catalog/_citation.html.erb +1 -1
  27. data/app/views/catalog/email.html.erb +2 -2
  28. data/app/views/catalog/sms.html.erb +2 -2
  29. data/app/views/kaminari/blacklight/_page.html.erb +1 -1
  30. data/blacklight.gemspec +1 -1
  31. data/config/locales/blacklight.ar.yml +0 -1
  32. data/config/locales/blacklight.ca.yml +0 -2
  33. data/config/locales/blacklight.de.yml +0 -1
  34. data/config/locales/blacklight.en.yml +0 -1
  35. data/config/locales/blacklight.es.yml +0 -1
  36. data/config/locales/blacklight.fr.yml +0 -1
  37. data/config/locales/blacklight.hu.yml +0 -1
  38. data/config/locales/blacklight.it.yml +0 -1
  39. data/config/locales/blacklight.nl.yml +0 -1
  40. data/config/locales/blacklight.pt-BR.yml +0 -1
  41. data/config/locales/blacklight.sq.yml +0 -1
  42. data/config/locales/blacklight.zh.yml +0 -1
  43. data/docker-compose.yml +0 -2
  44. data/lib/blacklight/solr/repository.rb +3 -1
  45. data/lib/blacklight/solr/response/params.rb +1 -1
  46. data/lib/blacklight/solr/search_builder_behavior.rb +2 -0
  47. data/lib/generators/blacklight/assets/importmap_generator.rb +2 -2
  48. data/lib/generators/blacklight/assets/sprockets_generator.rb +1 -1
  49. data/lib/generators/blacklight/assets_generator.rb +1 -1
  50. data/package.json +1 -1
  51. data/spec/components/blacklight/document_component_spec.rb +3 -3
  52. data/spec/components/blacklight/facet_component_spec.rb +1 -1
  53. data/spec/components/blacklight/response/view_type_component_spec.rb +1 -1
  54. data/spec/controllers/catalog_controller_spec.rb +2 -2
  55. data/spec/features/advanced_search_spec.rb +6 -0
  56. data/spec/features/citation_spec.rb +10 -0
  57. data/spec/features/sms_spec.rb +12 -0
  58. data/spec/models/blacklight/solr/response_spec.rb +1 -1
  59. data/spec/models/blacklight/solr/search_builder_spec.rb +13 -0
  60. data/spec/models/solr_document_spec.rb +6 -2
  61. data/spec/spec_helper.rb +0 -28
  62. data/spec/test_app_templates/Gemfile.extra +0 -1
  63. data/spec/views/catalog/_document.html.erb_spec.rb +1 -1
  64. data/spec/views/catalog/index.atom.builder_spec.rb +1 -1
  65. data/template.demo.rb +7 -7
  66. metadata +9 -5
@@ -55,7 +55,7 @@ module Blacklight
55
55
  def initialize_search_filter_controls
56
56
  fields = blacklight_config.facet_fields.select { |_k, v| v.include_in_advanced_search || v.include_in_advanced_search.nil? }
57
57
 
58
- fields.each do |_k, config|
58
+ fields.each_value do |config|
59
59
  display_facet = @response.aggregations[config.field]
60
60
  with_search_filter_control(config: config, display_facet: display_facet)
61
61
  end
@@ -1,13 +1,9 @@
1
- <%-
2
- # the data-doc-id attribute is used by our JS that converts to a checkbox/label.
3
- # we don't use the per-form csrf token
4
- -%>
1
+ <%- # we don't use the per-form csrf token -%>
5
2
  <%= form_tag(bookmark_path,
6
3
  authenticity_token: false,
7
4
  method: bookmarked? ? :delete : :put,
8
5
  class: "bookmark-toggle",
9
6
  data: {
10
- 'doc-id' => @document.id,
11
7
  present: t('blacklight.search.bookmarks.present'),
12
8
  absent: t('blacklight.search.bookmarks.absent'),
13
9
  inprogress: t('blacklight.search.bookmarks.inprogress')
@@ -20,6 +16,5 @@
20
16
  </div>
21
17
 
22
18
  <%= submit_tag(t(bookmarked? ? 'remove.button' : 'add.button', scope: 'blacklight.bookmarks'),
23
- id: "bookmark_toggle_#{@document.id.to_s.parameterize}",
24
19
  class: "bookmark-#{bookmarked? ? 'remove' : 'add'} btn btn-outline-secondary") %>
25
20
  <% end %>
@@ -8,11 +8,12 @@
8
8
  data-target="#<%= html_id %>"
9
9
  data-bs-target="#<%= html_id %>"
10
10
  aria-expanded="<%= @facet_field.collapsed? ? 'false' : 'true' %>"
11
+ arial-controls="<%= html_id %>"
11
12
  >
12
13
  <%= label %>
13
14
  </button>
14
15
  </h3>
15
- <div id="<%= html_id %>" aria-labelledby="<%= header_html_id %>" class="panel-collapse facet-content collapse <%= "show" unless @facet_field.collapsed? %>">
16
+ <div id="<%= html_id %>" role="region" aria-labelledby="<%= header_html_id %>" class="panel-collapse facet-content collapse <%= "show" unless @facet_field.collapsed? %>">
16
17
  <div class="card-body">
17
18
  <%= body %>
18
19
 
@@ -11,7 +11,7 @@ module Blacklight
11
11
  end
12
12
 
13
13
  def call
14
- tag.span(svg&.html_safe || default_icon, # rubocop:disable Rails/OutputSafety
14
+ tag.span(svg&.html_safe || default_icon, # rubocop:disable Rails/OutputSafety
15
15
  class: "blacklight-icons blacklight-icon-#{@name} #{@classes}".strip,
16
16
  'aria-hidden': (true if @aria_hidden))
17
17
  end
@@ -15,7 +15,6 @@
15
15
  aria: {
16
16
  controls: @panel_id,
17
17
  expanded: 'false',
18
- label: t('blacklight.search.facets.group.toggle'),
19
18
  } do %>
20
19
  <span data-show-label><%= t('blacklight.search.facets.group.open') %></span>
21
20
  <span data-hide-label><%= t('blacklight.search.facets.group.close') %></span>
@@ -1,8 +1,10 @@
1
- <% facet_group_names.each do |groupname| %>
2
- <% fields = facet_fields_in_group(groupname) %>
3
- <%= render group_component_class.new(id: groupname, fields: fields, response: response) do |component| %>
4
- <% component.with_body do %>
5
- <%= render Blacklight::FacetComponent.with_collection(fields, response: response) %>
1
+ <search>
2
+ <% facet_group_names.each do |groupname| %>
3
+ <% fields = facet_fields_in_group(groupname) %>
4
+ <%= render group_component_class.new(id: groupname, fields: fields, response: response) do |component| %>
5
+ <% component.with_body do %>
6
+ <%= render Blacklight::FacetComponent.with_collection(fields, response: response) %>
7
+ <% end %>
6
8
  <% end %>
7
9
  <% end %>
8
- <% end %>
10
+ </search>
@@ -1,39 +1,41 @@
1
- <%= form_with url: @url, local: true, method: @method, class: @classes.join(' '), scope: @prefix, role: 'search', **@form_options do |f| %>
2
- <%= render Blacklight::HiddenSearchStateComponent.new(params: @params) %>
3
- <% if search_fields.length > 1 %>
4
- <%= f.label :search_field, scoped_t('search_field.label'), class: 'sr-only visually-hidden' %>
5
- <% end %>
6
- <% before_input_groups.each do |input_group| %>
7
- <%= input_group %>
8
- <% end %>
9
- <div class="input-group">
10
- <%= prepend %>
11
-
1
+ <search>
2
+ <%= form_with url: @url, local: true, method: @method, class: @classes.join(' '), scope: @prefix, role: 'search', **@form_options do |f| %>
3
+ <%= render Blacklight::HiddenSearchStateComponent.new(params: @params) %>
12
4
  <% if search_fields.length > 1 %>
13
- <%= f.select(:search_field,
14
- options_for_select(search_fields, h(@search_field)),
15
- {},
16
- title: scoped_t('search_field.title'),
17
- class: "custom-select form-select search-field") %>
18
- <% elsif search_fields.length == 1 %>
19
- <%= f.hidden_field :search_field, value: search_fields.first.last %>
5
+ <%= f.label :search_field, scoped_t('search_field.label'), class: 'sr-only visually-hidden' %>
20
6
  <% end %>
21
-
22
- <%= f.label @query_param, scoped_t('search.label'), class: 'sr-only visually-hidden' %>
23
- <% if autocomplete_path.present? %>
24
- <auto-complete src="<%= autocomplete_path %>" for="autocomplete-popup" class="search-autocomplete-wrapper">
25
- <%= 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' } %>
26
- <ul id="autocomplete-popup" role="listbox" aria-label="<%= scoped_t('search.label') %>"></ul>
27
- </auto-complete>
28
- <% else %>
29
- <%= 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') } %>
7
+ <% before_input_groups.each do |input_group| %>
8
+ <%= input_group %>
30
9
  <% end %>
10
+ <div class="input-group">
11
+ <%= prepend %>
31
12
 
32
- <%= append %>
33
- <%= search_button || render(Blacklight::SearchButtonComponent.new(id: "#{@prefix}search", text: scoped_t('submit'))) %>
34
- </div>
35
- <% end %>
13
+ <% if search_fields.length > 1 %>
14
+ <%= f.select(:search_field,
15
+ options_for_select(search_fields, h(@search_field)),
16
+ {},
17
+ title: scoped_t('search_field.title'),
18
+ class: "custom-select form-select search-field") %>
19
+ <% elsif search_fields.length == 1 %>
20
+ <%= f.hidden_field :search_field, value: search_fields.first.last %>
21
+ <% end %>
36
22
 
37
- <% if advanced_search_enabled? %>
38
- <%= link_to t('blacklight.advanced_search.more_options'), @advanced_search_url, class: 'advanced_search btn btn-secondary'%>
39
- <% end %>
23
+ <%= f.label @query_param, scoped_t('search.label'), class: 'sr-only visually-hidden' %>
24
+ <% if autocomplete_path.present? %>
25
+ <auto-complete src="<%= autocomplete_path %>" for="autocomplete-popup" class="search-autocomplete-wrapper">
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>
28
+ </auto-complete>
29
+ <% else %>
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') } %>
31
+ <% end %>
32
+
33
+ <%= append %>
34
+ <%= search_button || render(Blacklight::SearchButtonComponent.new(id: "#{@prefix}search", text: scoped_t('submit'))) %>
35
+ </div>
36
+ <% end %>
37
+
38
+ <% if advanced_search_enabled? %>
39
+ <%= link_to t('blacklight.advanced_search.more_options'), @advanced_search_url, class: 'advanced_search btn btn-secondary'%>
40
+ <% end %>
41
+ </search>
@@ -1,6 +1,6 @@
1
1
  <div class="alert <%= @classes %>">
2
2
  <%= message %>
3
- <%= tag.button_tag button_contents, type: "button", class: "btn-close",
3
+ <%= tag.button button_contents, type: "button", class: "btn-close",
4
4
  data: { dismiss: "alert", bs_dismiss: "alert" },
5
5
  aria: { label: "Close" } %>
6
6
  </div>
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # A controller mixin that allows users to share their bookmarks.
4
+ # This is used to create a callback from refworks in the bookmarks_export_url helper in blacklight-marc
3
5
  module Blacklight::TokenBasedUser
4
6
  extend ActiveSupport::Concern
5
7
 
@@ -45,34 +47,18 @@ module Blacklight::TokenBasedUser
45
47
  end
46
48
 
47
49
  def export_secret_token
48
- secret_key_generator.generate_key('encrypted user session key')[0..(key_len - 1)]
50
+ secret_key_generator.generate_key('encrypted user session key', key_len)
49
51
  end
50
52
 
51
53
  def secret_key_generator
52
- @secret_key_generator ||= begin
53
- app = Rails.application
54
-
55
- secret_key_base = if app.respond_to?(:credentials)
56
- # Rails 5.2+
57
- app.credentials.secret_key_base
58
- else
59
- # Rails <= 5.1
60
- app.secrets.secret_key_base
61
- end
62
- ActiveSupport::KeyGenerator.new(secret_key_base)
63
- end
54
+ @secret_key_generator ||= ActiveSupport::KeyGenerator.new(Rails.application.secret_key_base)
64
55
  end
65
56
 
66
57
  def message_encryptor
67
58
  ActiveSupport::MessageEncryptor.new(export_secret_token)
68
59
  end
69
60
 
70
- # Ruby 2.4 requires keys of very particular lengths
71
61
  def key_len
72
- if ActiveSupport::MessageEncryptor.respond_to? :key_len
73
- ActiveSupport::MessageEncryptor.key_len
74
- else
75
- 0
76
- end
62
+ ActiveSupport::MessageEncryptor.key_len
77
63
  end
78
64
  end
@@ -36,7 +36,8 @@ module Blacklight::UrlHelperBehavior
36
36
  private :document_link_params
37
37
 
38
38
  ##
39
- # Attributes for a link that gives a URL we can use to track clicks for the current search session
39
+ # Attributes for a link that gives a URL we can use to track clicks for the current search session.
40
+ # We disable turbo prefetch (InstantClick), because since we replace the link with a form, it's just wasted.
40
41
  # @param [SolrDocument] document
41
42
  # @param [Integer] counter
42
43
  # @example
@@ -52,7 +53,7 @@ module Blacklight::UrlHelperBehavior
52
53
  return {} if path.nil?
53
54
 
54
55
  context_method = blacklight_config.track_search_session.storage == 'client' ? 'get' : 'post'
55
- { data: { context_href: path, context_method: context_method } }
56
+ { data: { context_href: path, context_method: context_method, turbo_prefetch: false } }
56
57
  end
57
58
 
58
59
  ##
@@ -18,11 +18,11 @@ export default class CheckboxSubmit {
18
18
  this.form = form
19
19
  }
20
20
 
21
- async clicked(evt) {
21
+ clicked(evt) {
22
22
  this.spanTarget.innerHTML = this.form.getAttribute('data-inprogress')
23
23
  this.labelTarget.setAttribute('disabled', 'disabled');
24
24
  this.checkboxTarget.setAttribute('disabled', 'disabled');
25
- const response = await fetch(this.formTarget.getAttribute('action'), {
25
+ fetch(this.formTarget.getAttribute('action'), {
26
26
  body: new FormData(this.formTarget),
27
27
  method: this.formTarget.getAttribute('method').toUpperCase(),
28
28
  headers: {
@@ -30,16 +30,17 @@ export default class CheckboxSubmit {
30
30
  'X-Requested-With': 'XMLHttpRequest',
31
31
  'X-CSRF-Token': document.querySelector('meta[name=csrf-token]')?.content
32
32
  }
33
- })
34
- this.labelTarget.removeAttribute('disabled')
35
- this.checkboxTarget.removeAttribute('disabled')
36
- if (response.ok) {
37
- const json = await response.json()
33
+ }).then((response) => {
34
+ if (response.ok) return response.json();
35
+ return Promise.reject('response was not ok')
36
+ }).then((json) => {
37
+ this.labelTarget.removeAttribute('disabled')
38
+ this.checkboxTarget.removeAttribute('disabled')
38
39
  this.updateStateFor(!this.checked)
39
40
  document.querySelector('[data-role=bookmark-counter]').innerHTML = json.bookmarks.count
40
- } else {
41
- alert('Error')
42
- }
41
+ }).catch((error) => {
42
+ this.handleError(error)
43
+ })
43
44
  }
44
45
 
45
46
  get checked() {
@@ -62,6 +63,10 @@ export default class CheckboxSubmit {
62
63
  return this.form.querySelector('[data-checkboxsubmit-target="span"]')
63
64
  }
64
65
 
66
+ handleError() {
67
+ alert("Unable to save the bookmark at this time.")
68
+ }
69
+
65
70
  updateStateFor(state) {
66
71
  this.checkboxTarget.checked = state
67
72
 
@@ -97,21 +97,35 @@ const Modal = (() => {
97
97
  }
98
98
 
99
99
  // Add the passed in contents to the modal and display it.
100
+ // We have specific handling so that scripts returned from the ajax call are executed.
101
+ // This enables adding a script like recaptcha to prevent bots from sending emails.
100
102
  modal.receiveAjax = function (contents) {
101
- const domparser = new DOMParser();
102
- const dom = domparser.parseFromString(contents, "text/html")
103
- // If there is a containerSelector on the document, use its children.
104
- let elements = dom.querySelectorAll(`${modal.containerSelector} > *`)
105
- if (elements.length == 0) {
106
- // If the containerSelector wasn't found, use the whole document
107
- elements = dom.body.childNodes
108
- }
109
-
110
- document.querySelector(`${modal.modalSelector} .modal-content`).replaceChildren(...elements)
111
-
112
- modal.show();
103
+ const domparser = new DOMParser();
104
+ const dom = domparser.parseFromString(contents, "text/html")
105
+ // If there is a containerSelector on the document, use its children.
106
+ let elements = dom.querySelectorAll(`${modal.containerSelector} > *`)
107
+ const frag = document.createDocumentFragment()
108
+ if (elements.length == 0) {
109
+ // If the containerSelector wasn't found, use the whole document
110
+ elements = dom.body.childNodes
111
+ }
112
+ elements.forEach((el) => frag.appendChild(el))
113
+ modal.activateScripts(frag)
114
+
115
+ document.querySelector(`${modal.modalSelector} .modal-content`).replaceChildren(frag)
116
+
117
+ modal.show();
113
118
  };
114
119
 
120
+ // DOMParser doesn't allow scripts to be executed. This fixes that.
121
+ modal.activateScripts = function (frag) {
122
+ frag.querySelectorAll('script').forEach((script) => {
123
+ const fixedScript = document.createElement('script')
124
+ fixedScript.src = script.src
125
+ fixedScript.async = false
126
+ script.parentNode.replaceChild(fixedScript, script)
127
+ })
128
+ }
115
129
 
116
130
  modal.modalAjaxLinkClick = function(e) {
117
131
  e.preventDefault();
@@ -27,6 +27,7 @@ SearchContext.handleSearchContextMethod = function(event) {
27
27
 
28
28
  // check for meta keys.. if set, we should open in a new tab
29
29
  if(event.metaKey || event.ctrlKey) {
30
+ form.dataset.turbo = "false";
30
31
  target = '_blank';
31
32
  }
32
33
 
@@ -65,6 +65,19 @@ module Blacklight
65
65
  end
66
66
  end
67
67
 
68
+ class Time < Value
69
+ def cast(input)
70
+ value = super
71
+ return if value.blank?
72
+
73
+ begin
74
+ ::Time.parse(value.to_s) # rubocop:disable Rails/TimeZone
75
+ rescue ArgumentError
76
+ Rails.logger&.info "Unable to parse time: #{value.inspect}"
77
+ end
78
+ end
79
+ end
80
+
68
81
  class Boolean < Value
69
82
  def cast(input)
70
83
  ActiveModel::Type::Boolean.new.cast(super)
@@ -106,6 +119,7 @@ module Blacklight
106
119
  register :boolean, Boolean
107
120
  register :string, String
108
121
  register :date, Date
122
+ register :time, Time
109
123
  register :array, Array
110
124
  register :json, JsonValue
111
125
  register :html, Html
@@ -1,6 +1,6 @@
1
1
  <%= render(Blacklight::AdvancedSearchFormComponent.new(
2
2
  url: search_action_url,
3
- classes: ['advanced', 'form-horizontal'],
3
+ classes: ['advanced'],
4
4
  params: search_state.params_for_search.except(:qt),
5
5
  response: @response
6
6
  )) %>
@@ -1,5 +1,5 @@
1
1
  <%= render Blacklight::System::ModalComponent.new do |component| %>
2
- <% component.title { t('blacklight.tools.citation') } %>
2
+ <% component.with_title { t('blacklight.tools.citation') } %>
3
3
 
4
4
  <%= render Blacklight::Document::CitationComponent.with_collection(@documents) if @documents.present? %>
5
5
  <% end %>
@@ -1,7 +1,7 @@
1
1
  <%= render Blacklight::System::ModalComponent.new do |component| %>
2
- <% component.title { t('blacklight.email.form.title') } %>
2
+ <% component.with_title { t('blacklight.email.form.title') } %>
3
3
 
4
- <% component.body do %>
4
+ <% component.with_body do %>
5
5
  <%= render 'email_form' %>
6
6
  <% end %>
7
7
  <% end %>
@@ -1,7 +1,7 @@
1
1
  <%= render Blacklight::System::ModalComponent.new do |component| %>
2
- <% component.title { t('blacklight.sms.form.title') } %>
2
+ <% component.with_title { t('blacklight.sms.form.title') } %>
3
3
 
4
- <% component.body do %>
4
+ <% component.with_body do %>
5
5
  <%= render 'sms_form' %>
6
6
  <% end %>
7
7
  <% end %>
@@ -11,7 +11,7 @@
11
11
 
12
12
  <li class="page-item <%= 'active' if page.current? %>">
13
13
  <% if page.current? %>
14
- <span class="page-link" aria-label="<%= t('views.pagination.aria.current_page', page: page_display) %>" aria-current="true"><%= page_display %></span>
14
+ <span class="page-link" aria-current="true"><%= page_display %><span class="sr-only visually-hidden"> <%= t('views.pagination.aria.current_page', page: page_display) %></span></span>
15
15
  <% else %>
16
16
  <%= link_to page_display, url, :remote => remote, :rel => page.next? ? 'next' : page.prev? ? 'prev' : nil, class: 'page-link', aria: { label: t('views.pagination.aria.go_to_page', page: page_display) } %>
17
17
  <% end %>
data/blacklight.gemspec CHANGED
@@ -34,7 +34,7 @@ Gem::Specification.new do |s|
34
34
  s.add_dependency "view_component", '>= 2.66', '< 4'
35
35
 
36
36
  s.add_development_dependency "rsolr", ">= 1.0.6", "< 3" # Library for interacting with rSolr.
37
- s.add_development_dependency "rspec-rails", "~> 6.0"
37
+ s.add_development_dependency "rspec-rails", "~> 6.1"
38
38
  s.add_development_dependency "rspec-collection_matchers", ">= 1.0"
39
39
  s.add_development_dependency 'axe-core-rspec'
40
40
  s.add_development_dependency "capybara", '~> 3'
@@ -101,7 +101,6 @@ ar:
101
101
  group:
102
102
  close: إخفاء الأوجه
103
103
  open: عرض الأوجه
104
- toggle: المزيد »
105
104
  missing: "[غير موجود]"
106
105
  more_html: المزيد <span class="sr-only visually-hidden">%{field_name}</span> »
107
106
  pivot:
@@ -190,8 +190,6 @@ ca:
190
190
  pivot:
191
191
  show: Mostrar
192
192
  hide: Amagar
193
- group:
194
- toggle: 'altres »'
195
193
  group:
196
194
  more: 'més »'
197
195
  filters:
@@ -91,7 +91,6 @@ de:
91
91
  group:
92
92
  close: Facetten ausblenden
93
93
  open: Facetten zeigen
94
- toggle: mehr »
95
94
  missing:
96
95
  - fehlt
97
96
  more_html: mehr <span class="sr-only visually-hidden">%{field_name}</span> »
@@ -191,7 +191,6 @@ en:
191
191
  show: Show
192
192
  hide: Hide
193
193
  group:
194
- toggle: Toggle facets
195
194
  open: Show facets
196
195
  close: Hide facets
197
196
  group:
@@ -91,7 +91,6 @@ es:
91
91
  group:
92
92
  close: Ocultar facetas
93
93
  open: Mostrar facetas
94
- toggle: más »
95
94
  missing: "[Falta]"
96
95
  more_html: más <span class="sr-only visually-hidden">%{field_name}</span> »
97
96
  pivot:
@@ -91,7 +91,6 @@ fr:
91
91
  group:
92
92
  close: Masquer les facettes
93
93
  open: Afficher les facettes
94
- toggle: plus »
95
94
  missing: "[manquante]"
96
95
  more_html: plus <span class="sr-only visually-hidden">%{field_name}</span> »
97
96
  pivot:
@@ -89,7 +89,6 @@ hu:
89
89
  group:
90
90
  close: Fazetek elrejtése
91
91
  open: Szempontok megjelenítése
92
- toggle: több »
93
92
  missing: "[Hiányzó]"
94
93
  more_html: több <span class="sr-only visually-hidden">%{field_name}</span> »
95
94
  pivot:
@@ -91,7 +91,6 @@ it:
91
91
  group:
92
92
  close: Nascondi sfaccettature
93
93
  open: Mostra sfaccettature
94
- toggle: altri »
95
94
  missing:
96
95
  - Mancante
97
96
  more_html: altri <span class="sr-only visually-hidden">%{field_name}</span> »
@@ -89,7 +89,6 @@ nl:
89
89
  group:
90
90
  close: Verberg facetten
91
91
  open: Toon facetten
92
- toggle: meer »
93
92
  missing: "[Ontbrekend]"
94
93
  more_html: Meer <span class="sr-only visually-hidden">%{field_name}</span> »
95
94
  pivot:
@@ -89,7 +89,6 @@ pt-BR:
89
89
  group:
90
90
  close: Ocultar facetas
91
91
  open: Mostrar facetas
92
- toggle: mais »
93
92
  missing:
94
93
  - Ausência
95
94
  more_html: mais <span class="sr-only visually-hidden">%{field_name}</span> »
@@ -89,7 +89,6 @@ sq:
89
89
  group:
90
90
  close: Fshih aspektet
91
91
  open: Trego aspektet
92
- toggle: më shumë »
93
92
  missing: "[Mungon]"
94
93
  more_html: Më shumë <span class="sr-only visually-hidden">%{field_name}</span> »
95
94
  pivot:
@@ -89,7 +89,6 @@ zh:
89
89
  group:
90
90
  close: 隐藏方面
91
91
  open: 显示方面
92
- toggle: 更多 »
93
92
  missing: "[未找到]"
94
93
  more_html: 更多 <span class="sr-only visually-hidden">%{field_name}</span> »
95
94
  pivot:
data/docker-compose.yml CHANGED
@@ -1,5 +1,3 @@
1
- version: "3.7"
2
-
3
1
  services:
4
2
  app:
5
3
  build:
@@ -21,7 +21,9 @@ module Blacklight::Solr
21
21
  # Execute a search query against solr
22
22
  # @param [Hash] params solr query parameters
23
23
  def search params = {}
24
- send_and_receive search_path(params), params.reverse_merge(qt: blacklight_config.qt)
24
+ request_params = params.reverse_merge({ qt: blacklight_config.qt })
25
+
26
+ send_and_receive search_path(request_params), request_params
25
27
  end
26
28
 
27
29
  # @param [Hash] request_params
@@ -31,7 +31,7 @@ module Blacklight::Solr::Response::Params
31
31
  defaults = {
32
32
  sort: single_valued_param(:'facet.sort'),
33
33
  limit: single_valued_param(:'facet.limit')&.to_i || 100,
34
- offset: single_valued_param(:'facet.offset')&.to_i || 0,
34
+ offset: single_valued_param(:'facet.offset').to_i,
35
35
  prefix: single_valued_param(:'facet.prefix')
36
36
  }
37
37
 
@@ -86,6 +86,8 @@ module Blacklight::Solr
86
86
  return unless search_state.query_param
87
87
 
88
88
  bool_query = search_field.clause_params.transform_values { |v| v.merge(query: search_state.query_param) }
89
+ solr_parameters["spellcheck.q"] ||= search_state.query_param
90
+
89
91
  solr_parameters.append_boolean_query(:must, bool_query)
90
92
  end
91
93
 
@@ -3,7 +3,7 @@
3
3
  module Blacklight
4
4
  module Assets
5
5
  class ImportmapGenerator < Rails::Generators::Base
6
- class_option :'bootstrap-version', type: :string, default: ENV.fetch('BOOTSTRAP_VERSION', '~> 5.1'), desc: "Set the generated app's bootstrap version"
6
+ class_option :'bootstrap-version', type: :string, default: ENV.fetch('BOOTSTRAP_VERSION', '~> 5.3'), desc: "Set the generated app's bootstrap version"
7
7
 
8
8
  # This could be skipped if you want to use webpacker
9
9
  def add_javascript_dependencies
@@ -16,7 +16,7 @@ module Blacklight
16
16
  <<~CONTENT
17
17
  pin "@github/auto-complete-element", to: "https://cdn.skypack.dev/@github/auto-complete-element"
18
18
  pin "@popperjs/core", to: "https://ga.jspm.io/npm:@popperjs/core@2.11.6/dist/umd/popper.min.js"
19
- pin "bootstrap", to: "https://ga.jspm.io/npm:bootstrap@#{(defined?(Bootstrap) && Bootstrap::VERSION) || '5.2.2'}/dist/js/bootstrap.js"
19
+ pin "bootstrap", to: "https://ga.jspm.io/npm:bootstrap@#{(defined?(Bootstrap) && Bootstrap::VERSION) || '5.3.2'}/dist/js/bootstrap.js"
20
20
  CONTENT
21
21
  end
22
22
 
@@ -3,7 +3,7 @@
3
3
  module Blacklight
4
4
  module Assets
5
5
  class SprocketsGenerator < Rails::Generators::Base
6
- class_option :'bootstrap-version', type: :string, default: ENV.fetch('BOOTSTRAP_VERSION', '~> 5.1'), desc: "Set the generated app's bootstrap version"
6
+ class_option :'bootstrap-version', type: :string, default: ENV.fetch('BOOTSTRAP_VERSION', '~> 5.3'), desc: "Set the generated app's bootstrap version"
7
7
 
8
8
  # This could be skipped if you want to use webpacker
9
9
  def add_javascript_dependencies
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Blacklight
4
4
  class AssetsGenerator < Rails::Generators::Base
5
- class_option :'bootstrap-version', type: :string, default: ENV.fetch('BOOTSTRAP_VERSION', '~> 5.1'), desc: "Set the generated app's bootstrap version"
5
+ class_option :'bootstrap-version', type: :string, default: ENV.fetch('BOOTSTRAP_VERSION', '~> 5.3'), desc: "Set the generated app's bootstrap version"
6
6
 
7
7
  def run_asset_pipeline_specific_generator
8
8
  generated_options = "--bootstrap-version='#{options[:'bootstrap-version']}'" if options[:'bootstrap-version']
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blacklight-frontend",
3
- "version": "8.0.1",
3
+ "version": "8.2.1",
4
4
  "description": "The frontend code and styles for Blacklight",
5
5
  "main": "app/assets/javascripts/blacklight",
6
6
  "module": "app/assets/javascripts/blacklight/blacklight.esm.js",