blacklight 8.1.0 → 8.2.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 (62) 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 +44 -21
  6. data/app/assets/javascripts/blacklight/blacklight.esm.js.map +1 -1
  7. data/app/assets/javascripts/blacklight/blacklight.js +44 -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_bar_component.html.erb +1 -1
  17. data/app/components/blacklight/system/flash_message_component.html.erb +1 -1
  18. data/app/controllers/concerns/blacklight/token_based_user.rb +5 -19
  19. data/app/helpers/blacklight/url_helper_behavior.rb +3 -2
  20. data/app/javascript/blacklight/bookmark_toggle.js +1 -1
  21. data/app/javascript/blacklight/checkbox_submit.js +15 -10
  22. data/app/javascript/blacklight/index.js +10 -5
  23. data/app/javascript/blacklight/modal.js +27 -13
  24. data/app/javascript/blacklight/search_context.js +1 -0
  25. data/app/values/blacklight/types.rb +14 -0
  26. data/app/views/catalog/_advanced_search_form.html.erb +1 -1
  27. data/app/views/catalog/_citation.html.erb +1 -1
  28. data/app/views/catalog/email.html.erb +2 -2
  29. data/app/views/catalog/sms.html.erb +2 -2
  30. data/app/views/kaminari/blacklight/_page.html.erb +1 -1
  31. data/blacklight.gemspec +1 -1
  32. data/config/locales/blacklight.ar.yml +0 -1
  33. data/config/locales/blacklight.ca.yml +0 -2
  34. data/config/locales/blacklight.de.yml +0 -1
  35. data/config/locales/blacklight.en.yml +0 -1
  36. data/config/locales/blacklight.es.yml +0 -1
  37. data/config/locales/blacklight.fr.yml +0 -1
  38. data/config/locales/blacklight.hu.yml +0 -1
  39. data/config/locales/blacklight.it.yml +0 -1
  40. data/config/locales/blacklight.nl.yml +0 -1
  41. data/config/locales/blacklight.pt-BR.yml +0 -1
  42. data/config/locales/blacklight.sq.yml +0 -1
  43. data/config/locales/blacklight.zh.yml +0 -1
  44. data/docker-compose.yml +0 -2
  45. data/lib/blacklight/solr/repository.rb +3 -1
  46. data/lib/blacklight/solr/response/params.rb +1 -1
  47. data/lib/blacklight/solr/search_builder_behavior.rb +2 -0
  48. data/lib/generators/blacklight/assets/importmap_generator.rb +2 -2
  49. data/lib/generators/blacklight/assets/sprockets_generator.rb +1 -1
  50. data/lib/generators/blacklight/assets_generator.rb +1 -1
  51. data/package.json +1 -1
  52. data/spec/controllers/catalog_controller_spec.rb +2 -2
  53. data/spec/features/advanced_search_spec.rb +6 -0
  54. data/spec/features/citation_spec.rb +10 -0
  55. data/spec/features/sms_spec.rb +12 -0
  56. data/spec/models/blacklight/solr/response_spec.rb +1 -1
  57. data/spec/models/blacklight/solr/search_builder_spec.rb +13 -0
  58. data/spec/models/solr_document_spec.rb +6 -2
  59. data/spec/spec_helper.rb +0 -28
  60. data/spec/test_app_templates/Gemfile.extra +0 -1
  61. data/template.demo.rb +7 -7
  62. metadata +9 -5
@@ -40,8 +40,8 @@
40
40
 
41
41
  <% if sort_fields_select %>
42
42
  <div class="form-group row mb-4">
43
- <%= content_tag :h2, t('blacklight.advanced_search.form.sort_label'), id: 'advanced-search-sort-label', class: 'col-md-3 col-form-label text-md-right' %>
44
- <div class="col">
43
+ <%= content_tag :h2, t('blacklight.advanced_search.form.sort_label'), id: 'advanced-search-sort-label', class: 'col-md-3 text-md-right' %>
44
+ <div class="col-md-9">
45
45
  <%= sort_fields_select %>
46
46
  </div>
47
47
  </div>
@@ -50,7 +50,7 @@
50
50
  <div class="form-group row">
51
51
  <div class="submit-buttons col-md-9 offset-md-3">
52
52
  <%= submit_tag t('blacklight.advanced_search.form.search_btn_html'), class: 'btn btn-primary advanced-search-submit', id: "advanced-search-submit" %>
53
- <%= button_tag t('blacklight.advanced_search.form.start_over_html'), type: 'reset', class: 'btn btn-link advanced-search-start-over' %>
53
+ <%= link_to t('blacklight.advanced_search.form.start_over_html'), request.path, :class =>"btn btn-link advanced-search-start-over" %>
54
54
  </div>
55
55
  </div>
56
56
  <% end %>
@@ -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>
@@ -23,7 +23,7 @@
23
23
  <% if autocomplete_path.present? %>
24
24
  <auto-complete src="<%= autocomplete_path %>" for="autocomplete-popup" class="search-autocomplete-wrapper">
25
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>
26
+ <ul id="autocomplete-popup" role="listbox" aria-label="<%= scoped_t('search.label') %>" hidden></ul>
27
27
  </auto-complete>
28
28
  <% else %>
29
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') } %>
@@ -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
  ##
@@ -1,4 +1,4 @@
1
- import CheckboxSubmit from 'blacklight/checkbox_submit'
1
+ import CheckboxSubmit from './checkbox_submit.js'
2
2
 
3
3
  const BookmarkToggle = (e) => {
4
4
  if (e.target.matches('[data-checkboxsubmit-target="checkbox"]')) {
@@ -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
 
@@ -1,8 +1,13 @@
1
- import BookmarkToggle from 'blacklight/bookmark_toggle'
2
- import ButtonFocus from 'blacklight/button_focus'
3
- import Modal from 'blacklight/modal'
4
- import SearchContext from 'blacklight/search_context'
5
- import Core from 'blacklight/core'
1
+ // ALL imports in this dir, including in files imported, should be RELATIVE
2
+ // paths to keep things working in the various ways these files get used, at
3
+ // both compile time and npm package run time.
4
+
5
+ import BookmarkToggle from './bookmark_toggle.js'
6
+ import ButtonFocus from './button_focus.js'
7
+ import Modal from './modal.js'
8
+ import SearchContext from './search_context.js'
9
+ import Core from './core.js'
10
+
6
11
 
7
12
  export default {
8
13
  BookmarkToggle,
@@ -52,7 +52,7 @@
52
52
  can be a turbo-stream that defines some HTML fragementsand where on the page to put them:
53
53
  https://turbo.hotwired.dev/handbook/streams
54
54
  */
55
- import ModalForm from 'blacklight/modalForm'
55
+ import ModalForm from './modalForm.js'
56
56
 
57
57
  const Modal = (() => {
58
58
  const modal = {}
@@ -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.0",
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",
@@ -54,7 +54,7 @@ RSpec.describe CatalogController, api: true do
54
54
  it "has no docs or facet values for query without results", integration: true do
55
55
  get :index, params: { q: 'sadfdsafasdfsadfsadfsadf' } # query for no results
56
56
  expect(assigns(:response).docs).to be_empty
57
- assigns(:response).aggregations.each do |_key, facet|
57
+ assigns(:response).aggregations.each_value do |facet|
58
58
  expect(facet.items).to be_empty
59
59
  end
60
60
  end
@@ -815,7 +815,7 @@ end
815
815
  def assert_facets_have_values(aggregations)
816
816
  expect(aggregations).not_to be_empty
817
817
  # should have at least one value for each facet
818
- aggregations.each do |_key, facet|
818
+ aggregations.each_value do |facet|
819
819
  expect(facet.items).to have_at_least(1).item
820
820
  end
821
821
  end