blacklight 8.0.1 → 8.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/.env +1 -1
  3. data/.github/workflows/ruby.yml +17 -4
  4. data/.rubocop.yml +4 -0
  5. data/.rubocop_todo.yml +82 -73
  6. data/VERSION +1 -1
  7. data/app/assets/javascripts/blacklight/blacklight.esm.js +44 -21
  8. data/app/assets/javascripts/blacklight/blacklight.esm.js.map +1 -1
  9. data/app/assets/javascripts/blacklight/blacklight.js +44 -21
  10. data/app/assets/javascripts/blacklight/blacklight.js.map +1 -1
  11. data/app/assets/stylesheets/blacklight/_mixins.scss +1 -1
  12. data/app/builders/blacklight/action_builder.rb +1 -1
  13. data/app/components/blacklight/advanced_search_form_component.html.erb +3 -3
  14. data/app/components/blacklight/advanced_search_form_component.rb +3 -3
  15. data/app/components/blacklight/document/bookmark_component.html.erb +1 -6
  16. data/app/components/blacklight/facet_field_component.html.erb +2 -1
  17. data/app/components/blacklight/icons/legacy_icon_component.rb +1 -1
  18. data/app/components/blacklight/response/facet_group_component.html.erb +0 -1
  19. data/app/components/blacklight/response/pagination_component.html.erb +1 -1
  20. data/app/components/blacklight/response/pagination_component.rb +6 -1
  21. data/app/components/blacklight/search_bar_component.html.erb +2 -2
  22. data/app/components/blacklight/system/flash_message_component.html.erb +1 -1
  23. data/app/controllers/concerns/blacklight/bookmarks.rb +1 -1
  24. data/app/controllers/concerns/blacklight/token_based_user.rb +5 -19
  25. data/app/helpers/blacklight/url_helper_behavior.rb +3 -2
  26. data/app/javascript/blacklight/bookmark_toggle.js +1 -1
  27. data/app/javascript/blacklight/checkbox_submit.js +15 -10
  28. data/app/javascript/blacklight/index.js +10 -5
  29. data/app/javascript/blacklight/modal.js +27 -13
  30. data/app/javascript/blacklight/search_context.js +1 -0
  31. data/app/models/concerns/blacklight/document/active_model_shim.rb +10 -0
  32. data/app/models/search.rb +6 -1
  33. data/app/services/blacklight/field_retriever.rb +13 -11
  34. data/app/values/blacklight/types.rb +14 -0
  35. data/app/views/catalog/_advanced_search_form.html.erb +1 -1
  36. data/app/views/catalog/_citation.html.erb +1 -1
  37. data/app/views/catalog/_show_tools.html.erb +1 -1
  38. data/app/views/catalog/email.html.erb +2 -2
  39. data/app/views/catalog/sms.html.erb +2 -2
  40. data/app/views/kaminari/blacklight/_page.html.erb +1 -1
  41. data/blacklight.gemspec +2 -3
  42. data/config/locales/blacklight.ar.yml +0 -1
  43. data/config/locales/blacklight.ca.yml +0 -2
  44. data/config/locales/blacklight.de.yml +0 -1
  45. data/config/locales/blacklight.en.yml +1 -1
  46. data/config/locales/blacklight.es.yml +0 -1
  47. data/config/locales/blacklight.fr.yml +0 -1
  48. data/config/locales/blacklight.hu.yml +0 -1
  49. data/config/locales/blacklight.it.yml +0 -1
  50. data/config/locales/blacklight.nl.yml +0 -1
  51. data/config/locales/blacklight.pt-BR.yml +0 -1
  52. data/config/locales/blacklight.sq.yml +0 -1
  53. data/config/locales/blacklight.zh.yml +0 -1
  54. data/docker-compose.yml +0 -2
  55. data/lib/blacklight/component.rb +1 -1
  56. data/lib/blacklight/configuration.rb +7 -1
  57. data/lib/blacklight/engine.rb +12 -0
  58. data/lib/blacklight/solr/repository.rb +16 -2
  59. data/lib/blacklight/solr/response/params.rb +1 -1
  60. data/lib/blacklight/solr/search_builder_behavior.rb +3 -0
  61. data/lib/generators/blacklight/assets/importmap_generator.rb +2 -2
  62. data/lib/generators/blacklight/assets/sprockets_generator.rb +1 -1
  63. data/lib/generators/blacklight/assets_generator.rb +2 -4
  64. data/lib/generators/blacklight/install_generator.rb +1 -3
  65. data/lib/generators/blacklight/templates/catalog_controller.rb +1 -0
  66. data/lib/generators/blacklight/templates/solr/conf/solrconfig.xml +69 -0
  67. data/package.json +1 -1
  68. data/spec/components/blacklight/facet_component_spec.rb +11 -1
  69. data/spec/components/blacklight/facet_item_pivot_component_spec.rb +2 -2
  70. data/spec/components/blacklight/response/pagination_component_spec.rb +53 -0
  71. data/spec/components/blacklight/search_context/server_applied_params_component_spec.rb +11 -1
  72. data/spec/controllers/catalog_controller_spec.rb +2 -2
  73. data/spec/features/advanced_search_spec.rb +61 -0
  74. data/spec/features/axe_spec.rb +5 -0
  75. data/spec/features/citation_spec.rb +10 -0
  76. data/spec/features/sms_spec.rb +12 -0
  77. data/spec/helpers/blacklight_helper_spec.rb +10 -5
  78. data/spec/models/blacklight/configurable_spec.rb +1 -1
  79. data/spec/models/blacklight/solr/repository_spec.rb +27 -0
  80. data/spec/models/blacklight/solr/response_spec.rb +1 -1
  81. data/spec/models/blacklight/solr/search_builder_spec.rb +21 -0
  82. data/spec/models/solr_document_spec.rb +6 -2
  83. data/spec/services/blacklight/field_retriever_spec.rb +17 -0
  84. data/spec/spec_helper.rb +1 -2
  85. data/spec/support/view_component_test_helpers.rb +14 -0
  86. data/spec/test_app_templates/Gemfile.extra +0 -1
  87. data/spec/views/catalog/_paginate_compact.html.erb_spec.rb +2 -0
  88. data/template.demo.rb +7 -7
  89. metadata +15 -21
@@ -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
 
@@ -29,6 +29,16 @@ module Blacklight::Document
29
29
  def find id
30
30
  repository.find(id).documents.first
31
31
  end
32
+
33
+ # In Rails 7.1+, needs this method
34
+ def composite_primary_key?
35
+ false
36
+ end
37
+
38
+ # In Rails 7.1+, needs this method
39
+ def has_query_constraints?
40
+ false
41
+ end
32
42
  end
33
43
 
34
44
  ##
data/app/models/search.rb CHANGED
@@ -3,7 +3,12 @@
3
3
  class Search < ApplicationRecord
4
4
  belongs_to :user, optional: true
5
5
 
6
- serialize :query_params, Blacklight::SearchParamsYamlCoder
6
+ if ::Rails.version.to_f >= 7.1
7
+ # non-deprecated coder: keyword arg for Rails 7.1+
8
+ serialize :query_params, coder: Blacklight::SearchParamsYamlCoder
9
+ else
10
+ serialize :query_params, Blacklight::SearchParamsYamlCoder
11
+ end
7
12
 
8
13
  # A Search instance is considered a saved search if it has a user_id.
9
14
  def saved?
@@ -22,17 +22,19 @@ module Blacklight
22
22
 
23
23
  # @return [Array]
24
24
  def fetch
25
- Array.wrap(
26
- if field_config.highlight
27
- retrieve_highlight
28
- elsif field_config.accessor
29
- retieve_using_accessor
30
- elsif field_config.values
31
- retrieve_values
32
- else
33
- retrieve_simple
34
- end
35
- )
25
+ if field_config.highlight
26
+ value = retrieve_highlight
27
+ end
28
+ if value.blank?
29
+ value = if field_config.accessor
30
+ retieve_using_accessor
31
+ elsif field_config.values
32
+ retrieve_values
33
+ else
34
+ retrieve_simple
35
+ end
36
+ end
37
+ Array.wrap(value)
36
38
  end
37
39
 
38
40
  private
@@ -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,2 +1,2 @@
1
- <% Blacklight.deprecation.warn('The partial _show_tools.html.erb will be removed in 9.0. Configure blacklight_config.show.show_tools_component instead (default Blacklight::Document::ShowToolsComponent).') unless local_assigns[:silence_deprecation] %>
1
+ <% Blacklight.deprecation.warn('The partial _show_tools.html.erb will be removed in Blacklight 9.0. Configure blacklight_config.show.show_tools_component instead (default Blacklight::Document::ShowToolsComponent).') unless local_assigns[:silence_deprecation] %>
2
2
  <%= render Blacklight::Document::ShowToolsComponent.new(document: document) %>
@@ -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
@@ -31,14 +31,13 @@ Gem::Specification.new do |s|
31
31
  s.add_dependency "kaminari", ">= 0.15" # the pagination (page 1,2,3, etc..) of our search results
32
32
  s.add_dependency "i18n", '>= 1.7.0' # added named parameters
33
33
  s.add_dependency "ostruct", '>= 0.3.2'
34
- s.add_dependency "view_component", '>= 2.66', '< 3.1'
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'
41
- s.add_development_dependency 'webdrivers'
42
41
  s.add_development_dependency 'selenium-webdriver'
43
42
  s.add_development_dependency 'engine_cart', '~> 2.1'
44
43
  s.add_development_dependency "equivalent-xml"
@@ -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:
@@ -244,6 +243,7 @@ en:
244
243
  more_options: More options
245
244
  any_of: 'Any of:'
246
245
  op:
246
+ label: search operator
247
247
  must: all
248
248
  should: any
249
249
  page_title: Advanced search - %{application_name}
@@ -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:
@@ -47,7 +47,7 @@ module Blacklight
47
47
 
48
48
  component_class.sidecar_files(extensions).each_with_object([]) do |path, memo|
49
49
  pieces = File.basename(path).split(".")
50
- app_path = "#{Rails.root}/#{path.slice(path.index(component_class.view_component_path)..-1)}"
50
+ app_path = Rails.root.join(path.slice(path.index(component_class.view_component_path)..-1).to_s).to_s
51
51
 
52
52
  memo << {
53
53
  path: File.exist?(app_path) ? app_path : path,
@@ -87,6 +87,10 @@ module Blacklight
87
87
  # @since v5.2.0
88
88
  # @return [String] The url path (relative to the solr base url) to use when requesting only a single document
89
89
  property :document_solr_path, default: 'get'
90
+ # @!attribute json_solr_path
91
+ # @since v7.34.0
92
+ # @return [String] The url path (relative to the solr base url) to use when using Solr's JSON Query DSL (as with the advanced search)
93
+ property :json_solr_path, default: 'advanced'
90
94
  # @!attribute document_unique_id_param
91
95
  # @since v5.2.0
92
96
  # @return [Symbol] The solr query parameter used for sending the unique identifiers for one or more documents
@@ -171,7 +175,9 @@ module Blacklight
171
175
  # component class used to render the search bar
172
176
  search_bar_component: nil,
173
177
  # component class used to render the header above the documents
174
- search_header_component: Blacklight::SearchHeaderComponent
178
+ search_header_component: Blacklight::SearchHeaderComponent,
179
+ # pagination parameters to pass to kaminari
180
+ pagination_options: Blacklight::Engine.config.blacklight.default_pagination_options.dup
175
181
  )
176
182
 
177
183
  # @!attribute show
@@ -6,6 +6,18 @@ module Blacklight
6
6
  class Engine < Rails::Engine
7
7
  engine_name "blacklight"
8
8
 
9
+ config.before_configuration do
10
+ # see https://github.com/fxn/zeitwerk#for_gem
11
+ # Blacklight puts a generator into LOCAL APP lib/generators, so tell
12
+ # zeitwerk to ignore the whole directory? If we're using a recent
13
+ # enough version of Rails to have zeitwerk config
14
+ #
15
+ # See: https://github.com/cbeer/engine_cart/issues/117
16
+ if Rails.try(:autoloaders).try(:main).respond_to?(:ignore)
17
+ Rails.autoloaders.main.ignore(Rails.root.join('lib/generators'))
18
+ end
19
+ end
20
+
9
21
  config.after_initialize do
10
22
  Blacklight::Configuration.initialize_default_configuration
11
23
  end
@@ -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 blacklight_config.solr_path, 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
@@ -78,7 +80,7 @@ module Blacklight::Solr
78
80
  # @return [Hash]
79
81
  # @!visibility private
80
82
  def build_solr_request(solr_params)
81
- if solr_params[:json].present?
83
+ if uses_json_query_dsl?(solr_params)
82
84
  {
83
85
  data: { params: solr_params.to_hash.except(:json) }.merge(solr_params[:json]).to_json,
84
86
  method: :post,
@@ -122,5 +124,17 @@ module Blacklight::Solr
122
124
  []
123
125
  end
124
126
  end
127
+
128
+ # @return [String]
129
+ def search_path(solr_params)
130
+ return blacklight_config.json_solr_path if blacklight_config.json_solr_path && uses_json_query_dsl?(solr_params)
131
+
132
+ blacklight_config.solr_path
133
+ end
134
+
135
+ # @return [Boolean]
136
+ def uses_json_query_dsl?(solr_params)
137
+ solr_params[:json].present?
138
+ end
125
139
  end
126
140
  end
@@ -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
 
@@ -83,7 +83,10 @@ module Blacklight::Solr
83
83
  end
84
84
 
85
85
  def add_search_field_with_json_query_parameters(solr_parameters)
86
+ return unless search_state.query_param
87
+
86
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
87
90
 
88
91
  solr_parameters.append_boolean_query(:must, bool_query)
89
92
  end
@@ -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
@@ -1,13 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'shellwords'
4
-
5
3
  module Blacklight
6
4
  class AssetsGenerator < Rails::Generators::Base
7
- 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"
8
6
 
9
7
  def run_asset_pipeline_specific_generator
10
- generated_options = "--bootstrap-version='#{Shellwords.escape(options[:'bootstrap-version'])}'" if options[:'bootstrap-version']
8
+ generated_options = "--bootstrap-version='#{options[:'bootstrap-version']}'" if options[:'bootstrap-version']
11
9
 
12
10
  generator = if defined?(Propshaft)
13
11
  'blacklight:assets:propshaft'
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'shellwords'
4
-
5
3
  module Blacklight
6
4
  class Install < Rails::Generators::Base
7
5
  source_root File.expand_path('../templates', __FILE__)
@@ -37,7 +35,7 @@ module Blacklight
37
35
  # Call external generator in AssetsGenerator, so we can
38
36
  # leave that callable seperately too.
39
37
  def copy_public_assets
40
- generated_options = "--bootstrap-version='#{Shellwords.escape(options[:'bootstrap-version'])}'" if options[:'bootstrap-version']
38
+ generated_options = "--bootstrap-version='#{options[:'bootstrap-version']}'" if options[:'bootstrap-version']
41
39
 
42
40
  generate "blacklight:assets", generated_options unless options[:'skip-assets']
43
41
  end
@@ -38,6 +38,7 @@ class <%= controller_name.classify %>Controller < ApplicationController
38
38
  # solr path which will be added to solr base url before the other solr params.
39
39
  #config.solr_path = 'select'
40
40
  #config.document_solr_path = 'get'
41
+ #config.json_solr_path = 'advanced'
41
42
 
42
43
  # items to show per page, each number in the array represent another option to choose from.
43
44
  #config.per_page = [10,20,50,100]