blacklight 9.0.0.beta7 → 9.0.0.beta8

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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/.docker/app/Dockerfile +2 -1
  3. data/.github/matrix.json +14 -3
  4. data/VERSION +1 -1
  5. data/app/assets/javascripts/blacklight/blacklight.esm.js +7 -4
  6. data/app/assets/javascripts/blacklight/blacklight.esm.js.map +1 -1
  7. data/app/assets/javascripts/blacklight/blacklight.js +7 -4
  8. data/app/assets/javascripts/blacklight/blacklight.js.map +1 -1
  9. data/app/components/blacklight/advanced_search_form_component.rb +2 -1
  10. data/app/components/blacklight/document_component.rb +10 -13
  11. data/app/components/blacklight/facets/filters_component.rb +1 -1
  12. data/app/components/blacklight/facets/suggest_component.rb +2 -3
  13. data/app/components/blacklight/metadata_field_component.html.erb +2 -2
  14. data/app/components/blacklight/metadata_field_component.rb +2 -1
  15. data/app/components/blacklight/metadata_field_layout_component.rb +9 -4
  16. data/app/components/blacklight/search_bar_component.html.erb +1 -1
  17. data/app/javascript/blacklight-frontend/modal.js +7 -4
  18. data/app/presenters/blacklight/document_presenter.rb +6 -5
  19. data/app/presenters/blacklight/facet_field_presenter.rb +10 -3
  20. data/app/presenters/blacklight/field_presenter.rb +4 -2
  21. data/app/presenters/blacklight/rendering/abstract_step.rb +7 -1
  22. data/app/presenters/blacklight/rendering/join.rb +9 -5
  23. data/app/presenters/blacklight/rendering/terminator.rb +1 -1
  24. data/app/views/catalog/_show_main_content.html.erb +9 -5
  25. data/app/views/catalog/index.html.erb +0 -1
  26. data/app/views/catalog/show.html.erb +2 -2
  27. data/config/locales/blacklight.en.yml +1 -1
  28. data/lib/blacklight/component.rb +2 -0
  29. data/lib/blacklight/configuration/facet_field.rb +2 -0
  30. data/lib/blacklight/configuration/view_config.rb +30 -16
  31. data/lib/blacklight/configuration.rb +56 -5
  32. data/lib/blacklight/search_state/pivot_filter_field.rb +1 -1
  33. data/lib/blacklight/solr/field_reflection_search_builder.rb +11 -0
  34. data/lib/blacklight/solr/repository.rb +5 -5
  35. data/lib/blacklight/solr/search_builder_behavior.rb +19 -2
  36. data/lib/blacklight/solr/single_doc_search_builder.rb +25 -0
  37. data/lib/generators/blacklight/templates/catalog_controller.rb +26 -4
  38. data/lib/generators/blacklight/templates/solr/conf/solrconfig.xml +0 -67
  39. data/package.json +1 -1
  40. data/spec/components/blacklight/document_component_spec.rb +0 -7
  41. data/spec/components/blacklight/facets/filters_component_spec.rb +2 -2
  42. data/spec/components/blacklight/facets/suggest_component_spec.rb +13 -0
  43. data/spec/components/blacklight/search_bar_component_spec.rb +24 -1
  44. data/spec/controllers/blacklight/catalog_spec.rb +1 -1
  45. data/spec/features/advanced_search_spec.rb +39 -20
  46. data/spec/models/blacklight/configuration_spec.rb +126 -0
  47. data/spec/models/blacklight/solr/repository_spec.rb +6 -0
  48. data/spec/models/blacklight/solr/search_builder_behavior_spec.rb +52 -6
  49. data/spec/presenters/blacklight/document_presenter_spec.rb +3 -3
  50. data/spec/presenters/blacklight/field_presenter_spec.rb +103 -22
  51. data/spec/presenters/blacklight/rendering/pipeline_spec.rb +130 -14
  52. metadata +4 -5
  53. data/app/views/shared/_sitelinks_search_box.html.erb +0 -12
  54. data/spec/features/sitelinks_search_box_spec.rb +0 -13
@@ -160,11 +160,14 @@ const Modal = (() => {
160
160
 
161
161
  // Make sure user-agent dismissal of html 'dialog', etc `esc` key, triggers
162
162
  // our hide logic, including events and scroll restoration.
163
- modal.target().addEventListener('cancel', (e) => {
164
- e.preventDefault(); // 'hide' will close the modal unless cancelled
163
+ const modalDom = modal.target();
164
+ if (modalDom) {
165
+ modal.target().addEventListener('cancel', (e) => {
166
+ e.preventDefault(); // 'hide' will close the modal unless cancelled
165
167
 
166
- modal.hide();
167
- });
168
+ modal.hide();
169
+ });
170
+ }
168
171
  };
169
172
 
170
173
  modal.hide = function (el) {
@@ -44,11 +44,11 @@ module Blacklight
44
44
  #
45
45
  # @return [String]
46
46
  def heading
47
- return field_value(view_config.title_field) if view_config.title_field.is_a? Blacklight::Configuration::Field
47
+ return field_value(view_config.title_field, join: true).first if view_config.title_field.is_a? Blacklight::Configuration::Field
48
48
 
49
49
  fields = Array.wrap(view_config.title_field) + [configuration.document_model.unique_key]
50
50
  f = fields.lazy.map { |field| field_config(field) }.detect { |field_config| field_presenter(field_config).any? }
51
- f ? field_value(f, except_operations: [Rendering::HelperMethod]) : ""
51
+ f ? field_value(f, except_operations: [Rendering::HelperMethod], join: true).first : ""
52
52
  end
53
53
 
54
54
  ##
@@ -58,12 +58,12 @@ module Blacklight
58
58
  # @see #document_heading
59
59
  # @return [String]
60
60
  def html_title
61
- return field_value(view_config.html_title_field) if view_config.html_title_field.is_a? Blacklight::Configuration::Field
61
+ return field_value(view_config.html_title_field, join: true).first if view_config.html_title_field.is_a? Blacklight::Configuration::Field
62
62
 
63
63
  if view_config.html_title_field
64
64
  fields = Array.wrap(view_config.html_title_field) + [configuration.document_model.unique_key]
65
65
  f = fields.lazy.map { |field| field_config(field) }.detect { |field_config| field_presenter(field_config).any? }
66
- field_value(f)
66
+ field_value(f, join: true).first
67
67
  else
68
68
  heading
69
69
  end
@@ -93,8 +93,9 @@ module Blacklight
93
93
  # @param [Configuration::Field] field_config
94
94
  # @param [Hash] options
95
95
  # @option options [String] :value
96
+ # @return [Array]
96
97
  def field_value field_config, options = {}
97
- field_presenter(field_config, options).render
98
+ Array.wrap(field_presenter(field_config, options).render)
98
99
  end
99
100
 
100
101
  def thumbnail_presenter_class
@@ -4,18 +4,18 @@ module Blacklight
4
4
  class FacetFieldPresenter
5
5
  attr_reader :facet_field, :display_facet, :view_context, :search_state
6
6
 
7
- delegate :key, :suggest, to: :facet_field
7
+ delegate :key, to: :facet_field
8
8
  delegate :field_name, to: :display_facet
9
9
 
10
10
  # @param [Blacklight::Configuration::FacetField] facet_field
11
11
  # @param [Blacklight::Solr::Response::Facets::FacetField] display_facet
12
12
  # @param [#search_action_path,#facet_field_presenter] view_context
13
13
  # @param [Blacklight::SearchState] search_state
14
- def initialize(facet_field, display_facet, view_context, search_state = view_context.search_state)
14
+ def initialize(facet_field, display_facet, view_context, search_state = nil)
15
15
  @facet_field = facet_field
16
16
  @display_facet = display_facet
17
17
  @view_context = view_context
18
- @search_state = search_state
18
+ @search_state = search_state || view_context&.search_state
19
19
  end
20
20
 
21
21
  # @param [Blacklight::Solr::Response::Facets::FacetItem, String] facet_item
@@ -23,6 +23,13 @@ module Blacklight
23
23
  facet_field.item_presenter.new(facet_item, facet_field, view_context, key, search_state)
24
24
  end
25
25
 
26
+ # Is facet suggest feature configured on for this facet, or by global default.
27
+ #
28
+ # @return [Boolean]
29
+ def suggest?
30
+ !!(facet_field.suggest.nil? ? blacklight_config.default_facet_suggest : facet_field.suggest)
31
+ end
32
+
26
33
  def collapsed?
27
34
  !active? && facet_field.collapse
28
35
  end
@@ -33,9 +33,11 @@ module Blacklight
33
33
 
34
34
  delegate :key, :component, to: :field_config
35
35
 
36
- # @return [String]
36
+ # @return [Array<String>]
37
37
  def render
38
- Rendering::Pipeline.new(values, field_config, document, view_context, pipeline_steps, options).render
38
+ Array.wrap(
39
+ Rendering::Pipeline.new(values, field_config, document, view_context, pipeline_steps, options).render
40
+ )
39
41
  end
40
42
 
41
43
  # @return [Enumerable]
@@ -22,7 +22,13 @@ module Blacklight
22
22
  end
23
23
 
24
24
  def html?
25
- options[:format].nil? || options[:format].to_s == 'html'
25
+ format.nil? || format.to_s == 'html'
26
+ end
27
+
28
+ def format
29
+ return options[:format] unless context.respond_to?(:search_state)
30
+
31
+ options[:format] || context.search_state&.params&.dig(:format)
26
32
  end
27
33
  end
28
34
  end
@@ -5,12 +5,11 @@ module Blacklight
5
5
  class Join < AbstractStep
6
6
  def render
7
7
  options = config.separator_options || {}
8
- if values.one? || values.none?
9
- next_step(values.first)
10
- elsif !html?
11
- next_step(values.to_sentence(options))
12
- else
8
+
9
+ if join? && html? && values.many?
13
10
  next_step(values.map { |x| x.html_safe? ? x : html_escape(x) }.to_sentence(options).html_safe)
11
+ else
12
+ next_step(values)
14
13
  end
15
14
  end
16
15
 
@@ -19,6 +18,11 @@ module Blacklight
19
18
  def html_escape(*)
20
19
  ERB::Util.html_escape(*)
21
20
  end
21
+
22
+ # @return [Boolean]
23
+ def join?
24
+ options[:join] || config.join || config.separator_options
25
+ end
22
26
  end
23
27
  end
24
28
  end
@@ -4,7 +4,7 @@ module Blacklight
4
4
  module Rendering
5
5
  class Terminator < AbstractStep
6
6
  def render
7
- values
7
+ Array.wrap values
8
8
  end
9
9
  end
10
10
  end
@@ -1,14 +1,18 @@
1
- <%= render blacklight_config.view_config(:show).document_header_component.new(document: @document, search_context: @search_context, search_session: search_session) %>
2
- <% @page_title = t('blacklight.search.show.title', document_title: document_presenter(@document).html_title, application_name: application_name).html_safe %>
1
+ <%# locals: (presenter: nil) %>
2
+ <% presenter ||= document_presenter(@document) %>
3
+
4
+ <% @page_title = t('blacklight.search.show.title', document_title: presenter.html_title, application_name: application_name).html_safe %>
3
5
  <% content_for(:head) { render_link_rel_alternates } %>
4
6
 
5
- <% document_component = blacklight_config.view_config(:show).document_component -%>
6
- <%= render document_component.new(document: document_presenter(@document), component: :div, show: true, partials: blacklight_config.view_config(:show).partials) do |component| %>
7
+ <%= render presenter.view_config.document_header_component.new(document: @document, search_context: @search_context, search_session: search_session) %>
8
+
9
+ <% document_component = presenter.view_config.document_component -%>
10
+ <%= render document_component.new(id: 'document', document: presenter, component: :div, show: true, partials: presenter.view_config.partials) do |component| %>
7
11
  <% component.with_title(as: 'h1', classes: '', link_to_document: false, actions: false) %>
8
12
  <% component.with_footer do %>
9
13
  <% if @document.respond_to?(:export_as_openurl_ctx_kev) %>
10
14
  <!-- COinS, for Zotero among others. -->
11
- <span class="Z3988" title="<%= @document.export_as_openurl_ctx_kev(document_presenter(@document).display_type) %>"></span>
15
+ <span class="Z3988" title="<%= @document.export_as_openurl_ctx_kev(presenter.display_type) %>"></span>
12
16
  <% end %>
13
17
  <% end %>
14
18
  <% end %>
@@ -11,7 +11,6 @@
11
11
  <% unless has_search_parameters? %>
12
12
  <%# if there are no input/search related params, display the "home" partial -%>
13
13
  <%= render 'home' %>
14
- <%= render 'shared/sitelinks_search_box' %>
15
14
  <% else %>
16
15
  <%= render 'search_results' %>
17
16
  <% end %>
@@ -1,6 +1,6 @@
1
- <%= render 'show_main_content' %>
1
+ <% presenter = document_presenter(@document) %>
2
+ <%= render 'show_main_content', presenter: presenter %>
2
3
 
3
4
  <% content_for(:sidebar) do %>
4
- <% presenter = document_presenter(@document) %>
5
5
  <%= render presenter.view_config.sidebar_component.new(presenter: presenter) %>
6
6
  <% end %>
@@ -11,7 +11,7 @@ en:
11
11
  sort_label: Sort results by
12
12
  start_over_html: Start over
13
13
  title: Advanced search
14
- more_options: More options
14
+ more_options: Advanced search
15
15
  op:
16
16
  label: search operator
17
17
  must: all
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'view_component/version'
4
+
3
5
  module Blacklight
4
6
  class Component < ViewComponent::Base
5
7
  class << self
@@ -16,6 +16,8 @@ module Blacklight
16
16
  # @return [Boolean] whether to show the facet to the user or not (very similar to the more generic if/unless)
17
17
  # @!attribute index_range
18
18
  # @return [Enumerable] a list of facet prefixes (default: A-Z) to allow users to 'jump' to particular values
19
+ # @!attribute suggest
20
+ # @return [Boolean] whether to display a suggest/autocomplete on the detailed facet view that allows users to filter facet values
19
21
  # @!attribute date
20
22
  # @return [Symbol|Hash] the i18n localization option for a date or time value; used as the second parameter for the I18n.l method
21
23
  # @!attribute link_to_facet
@@ -8,6 +8,14 @@ class Blacklight::Configuration
8
8
  # @return [Class] document presenter class used by helpers and views
9
9
  # @!attribute document_component
10
10
  # @return [Class] component class used to render a document; defaults to Blacklight::DocumentComponent
11
+ # @!attribute document_title_component
12
+ # @return [Class] component class used to render a document title
13
+ # @!attribute document_metadata_component
14
+ # @return [Class] component class used to render the document metadata
15
+ # @!attribute document_thumbnail_component
16
+ # @return [Class] component class used to render a document thumbnail
17
+ # @!attribute document_embed_component
18
+ # @return [Class] component class used to render a document embed
11
19
  # @!attribute title_field
12
20
  # @return [String, Symbol] solr field to use to render a document title
13
21
  # @!attribute display_type_field
@@ -46,19 +54,33 @@ class Blacklight::Configuration
46
54
  end
47
55
  end
48
56
 
57
+ # Provide backwards compatibility with the configuration keys without the document_ prefix
58
+ def title_component(*) = document_title_component(*)
59
+ def metadata_component(*) = document_metadata_component(*)
60
+ def thumbnail_component(*) = document_thumbnail_component(*)
61
+ def embed_component(*) = document_embed_component(*)
62
+
63
+ def title_component=(value)
64
+ self.document_title_component = value
65
+ end
66
+
67
+ def metadata_component=(value)
68
+ self.document_metadata_component = value
69
+ end
70
+
71
+ def thumbnail_component=(value)
72
+ self.document_thumbnail_component = value
73
+ end
74
+
75
+ def embed_component=(value)
76
+ self.document_embed_component = value
77
+ end
78
+
49
79
  class Show < ViewConfig
50
80
  # @!attribute route
51
81
  # @return [Hash] Default route parameters for 'show' requests.
52
82
  # Set this to a hash with additional arguments to merge into the route,
53
83
  # or set `controller: :current` to route to the current controller.
54
-
55
- def document_presenter_class
56
- super || Blacklight::ShowPresenter
57
- end
58
-
59
- def to_h
60
- super.merge(document_presenter_class: document_presenter_class)
61
- end
62
84
  end
63
85
 
64
86
  class Index < ViewConfig
@@ -69,14 +91,6 @@ class Blacklight::Configuration
69
91
  # see Blacklight::Catalog#additional_response_formats for information about the OpenStruct data
70
92
  # @!attribute collection_actions
71
93
  # @return [String, Symbol]
72
-
73
- def document_presenter_class
74
- super || Blacklight::IndexPresenter
75
- end
76
-
77
- def to_h
78
- super.merge(document_presenter_class: document_presenter_class)
79
- end
80
94
  end
81
95
  end
82
96
  end
@@ -73,7 +73,8 @@ module Blacklight
73
73
  # @!attribute json_solr_path
74
74
  # @since v7.34.0
75
75
  # @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)
76
- property :json_solr_path, default: 'advanced'
76
+ # @note You can configure a separate custom 'advanced' requestHandler in solrconfig.xml if desired, but it isn't necessary; the default 'select' handler will work.
77
+ property :json_solr_path, default: 'select'
77
78
  # @!attribute document_unique_id_param
78
79
  # @since v5.2.0
79
80
  # @return [Symbol] The solr query parameter used for sending the unique identifiers for one or more documents
@@ -147,11 +148,15 @@ module Blacklight
147
148
  # @return [Blacklight::Configuration::ViewConfig::Index]
148
149
  property :index, default: ViewConfig::Index.new(
149
150
  # document presenter class used by helpers and views
150
- document_presenter_class: nil,
151
+ document_presenter_class: Blacklight::IndexPresenter,
151
152
  # document presenter used for json responses
152
153
  json_presenter_class: Blacklight::JsonPresenter,
153
154
  # component class used to render a document
154
155
  document_component: Blacklight::DocumentComponent,
156
+ document_embed_component: nil,
157
+ document_metadata_component: Blacklight::DocumentMetadataComponent,
158
+ document_thumbnail_component: Blacklight::Document::ThumbnailComponent,
159
+ document_title_component: Blacklight::DocumentTitleComponent,
155
160
  sidebar_component: Blacklight::Search::SidebarComponent,
156
161
  dropdown_component: Blacklight::System::DropdownComponent,
157
162
  # solr field to use to render a document title
@@ -187,8 +192,9 @@ module Blacklight
187
192
  # @return [Blacklight::Configuration::ViewConfig::Show]
188
193
  property :show, default: ViewConfig::Show.new(
189
194
  # document presenter class used by helpers and views
190
- document_presenter_class: nil,
195
+ document_presenter_class: Blacklight::ShowPresenter,
191
196
  document_component: Blacklight::DocumentComponent,
197
+ document_thumbnail_component: nil,
192
198
  show_tools_component: Blacklight::Document::ShowToolsComponent,
193
199
  show_header_tools_component: nil,
194
200
  document_header_component: Blacklight::Document::PageHeaderComponent,
@@ -269,6 +275,10 @@ module Blacklight
269
275
  # @since v5.10.0
270
276
  # @return [Integer]
271
277
  property :default_facet_limit, default: 10
278
+ # @!attribute default_facet_suggest
279
+ # @since v9.0.0
280
+ # @return [Boolean]
281
+ property :default_facet_suggest, default: true
272
282
  # @!attribute default_more_limit
273
283
  # @since v7.0.0
274
284
  # @return [Integer]
@@ -299,8 +309,13 @@ module Blacklight
299
309
 
300
310
  # @!attribute advanced_search
301
311
  # @since v7.15.0
302
- # @return [#enabled]
303
- property :advanced_search, default: OpenStruct.new(enabled: false)
312
+ # @return [OpenStructWithHashAccess] Configuration for advanced search, including:
313
+ # enabled: (Boolean) whether advanced search is enabled
314
+ # form_solr_parameters: (Hash) optional parameters to send to Solr for the advanced search
315
+ # form; can override values that are set automatically via the
316
+ # #copy_facet_field_config_to_advanced! method
317
+ property :advanced_search, default: OpenStructWithHashAccess.new(enabled: true,
318
+ form_solr_parameters: {})
304
319
 
305
320
  # @!attribute enable_search_bar_autofocus
306
321
  # @since v7.2.0
@@ -457,6 +472,42 @@ module Blacklight
457
472
  facet_fields.map { |_facet, opts| opts[:group] }.uniq
458
473
  end
459
474
 
475
+ # Use existing search field configs to automatically prepare fields for use
476
+ # by the advanced search form.
477
+ def copy_search_field_config_to_advanced!
478
+ search_fields.each_value do |field|
479
+ next if field.include_in_advanced_search == false
480
+ next if field.clause_params
481
+
482
+ field.clause_params = {}
483
+ field.clause_params[:edismax] = field.solr_parameters.dup || {}
484
+ end
485
+ end
486
+
487
+ # Use existing facet field configs to automatically prepare fields for use
488
+ # by the advanced search form. If more specific config is needed, e.g., to
489
+ # set the facet limit for one field to a value other than -1, it can be
490
+ # expressed in the configuration in advanced_search.form_solr_parameters
491
+ def copy_facet_field_config_to_advanced!
492
+ advanced_search.form_solr_parameters ||= {}
493
+ advanced_search.form_solr_parameters['facet.sort'] ||= 'count'
494
+ advanced_search.form_solr_parameters['facet.field'] ||= []
495
+
496
+ facet_fields.each_value do |field|
497
+ next if field.include_in_advanced_search == false
498
+ # Skip query-type and pivot facets that can't be requested via facet.field
499
+ next if field.query || field.pivot || field.range
500
+
501
+ # Add the facet field to the advanced search configuration
502
+ advanced_search.form_solr_parameters['facet.field'] << field.field unless
503
+ advanced_search.form_solr_parameters['facet.field'].include?(field.field)
504
+
505
+ # Set the facet field's limit to -1 to show ALL values in advanced search
506
+ advanced_search.form_solr_parameters["f.#{field.field}.facet.limit"] = -1 unless
507
+ advanced_search.form_solr_parameters["f.#{field.field}.facet.limit"]
508
+ end
509
+ end
510
+
460
511
  # Add any configured facet fields to the default solr parameters hash
461
512
  # @overload add_facet_fields_to_solr_request!
462
513
  # add all facet fields to the solr request
@@ -102,7 +102,7 @@ module Blacklight
102
102
  end
103
103
  queries.uniq!
104
104
  end
105
- [(queries - existing)]
105
+ [queries - existing]
106
106
  end
107
107
  end
108
108
 
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Blacklight::Solr
4
+ class FieldReflectionSearchBuilder < SearchBuilder
5
+ self.default_processor_chain = [:add_params]
6
+
7
+ def add_params(request)
8
+ request.reverse_merge!({ fl: '*', 'json.nl' => 'map' })
9
+ end
10
+ end
11
+ end
@@ -7,8 +7,7 @@ module Blacklight::Solr
7
7
  # @param [String] id document's unique key value
8
8
  # @param [Hash] params additional solr query parameters
9
9
  def find id, params = {}
10
- doc_params = params.reverse_merge(blacklight_config.default_document_solr_params)
11
- .merge(blacklight_config.document_unique_id_param => id)
10
+ doc_params = SingleDocSearchBuilder.new(self, id, params)
12
11
 
13
12
  solr_response = send_and_receive blacklight_config.document_solr_path || blacklight_config.solr_path, doc_params
14
13
  raise Blacklight::Exceptions::RecordNotFound if solr_response.documents.empty?
@@ -24,14 +23,14 @@ module Blacklight::Solr
24
23
 
25
24
  ##
26
25
  # Execute a search query against solr
27
- # @param [Hash] params solr query parameters
26
+ # @param [Hash,Blacklight::SearchBuilder] params solr query parameters
28
27
  # @param [String] path solr request handler path
29
28
  def search pos_params = nil, path: nil, params: nil, **kwargs
30
29
  if pos_params
31
30
  Blacklight.deprecation.warn("Passing positional arguments to search() is deprecated. Use the params kwarg instead.")
32
31
  end
33
32
 
34
- request_params = (params || pos_params).reverse_merge(kwargs).reverse_merge({ qt: blacklight_config.qt })
33
+ request_params = (params || pos_params || {}).reverse_merge(kwargs).reverse_merge({ qt: blacklight_config.qt })
35
34
 
36
35
  send_and_receive(path || default_search_path(request_params), request_params)
37
36
  end
@@ -47,7 +46,8 @@ module Blacklight::Solr
47
46
  # Gets a list of available fields
48
47
  # @return [Hash]
49
48
  def reflect_fields
50
- send_and_receive('admin/luke', params: { fl: '*', 'json.nl' => 'map' })['fields']
49
+ doc_params = FieldReflectionSearchBuilder.new(self)
50
+ send_and_receive('admin/luke', doc_params)['fields']
51
51
  end
52
52
 
53
53
  ##
@@ -10,7 +10,7 @@ module Blacklight::Solr
10
10
  :add_query_to_solr, :add_facet_fq_to_solr,
11
11
  :add_facetting_to_solr, :add_solr_fields_to_query, :add_paging_to_solr,
12
12
  :add_sorting_to_solr, :add_group_config_to_solr,
13
- :add_adv_search_clauses,
13
+ :add_adv_search_clauses, :add_facets_for_advanced_search_form,
14
14
  :add_additional_filters
15
15
  ]
16
16
  end
@@ -95,6 +95,13 @@ module Blacklight::Solr
95
95
  def add_adv_search_clauses(solr_parameters)
96
96
  return if search_state.clause_params.blank?
97
97
 
98
+ # We need to specify lucene as the top-level defType when using JSON Query DSL in Solr versions
99
+ # between 7.2.0 & 9.4.0. After 9.4.0 this is no longer necessary, but also not harmful to include.
100
+ solr_parameters[:defType] = 'lucene'
101
+
102
+ # Disable spellcheck, which doesn't work when using JSON Query DSL
103
+ solr_parameters[:spellcheck] = 'false'
104
+
98
105
  defaults = { must: [], must_not: [], should: [] }
99
106
  default_op = blacklight_params[:op]&.to_sym || :must
100
107
  solr_parameters[:mm] = 1 if default_op == :should && search_state.clause_params.values.any? { |clause| }
@@ -117,6 +124,16 @@ module Blacklight::Solr
117
124
  [op, field.clause_params.transform_values { |v| v.merge(query: clause[:query]) }]
118
125
  end
119
126
 
127
+ # Merge the advanced search form parameters into the solr parameters
128
+ # @param [Hash] solr_parameters the current solr parameters
129
+ # @return [Hash] the solr parameters with the additional advanced search form parameters
130
+ def add_facets_for_advanced_search_form(solr_parameters)
131
+ return unless search_state.controller&.action_name == 'advanced_search' &&
132
+ blacklight_config.advanced_search[:form_solr_parameters]
133
+
134
+ solr_parameters.merge!(blacklight_config.advanced_search[:form_solr_parameters])
135
+ end
136
+
120
137
  ##
121
138
  # Add any existing facet limits, stored in app-level HTTP query
122
139
  # as :f, to solr as appropriate :fq query.
@@ -243,7 +260,7 @@ module Blacklight::Solr
243
260
 
244
261
  # Look up facet limit for given facet_field. Will look at config, and
245
262
  # if config is 'true' will look up from Solr @response if available. If
246
- # no limit is avaialble, returns nil. Used from #add_facetting_to_solr
263
+ # no limit is available, returns nil. Used from #add_facetting_to_solr
247
264
  # to supply f.fieldname.facet.limit values in solr request (no @response
248
265
  # available), and used in display (with @response available) to create
249
266
  # a facet paginator with the right limit.
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Blacklight::Solr
4
+ class SingleDocSearchBuilder < SearchBuilder
5
+ self.default_processor_chain = [:add_defaults, :add_qt, :add_unique_id]
6
+
7
+ def initialize(scope, id, other_params)
8
+ @other_params = other_params
9
+ @id = id
10
+ super(scope)
11
+ end
12
+
13
+ def add_defaults(request)
14
+ request.reverse_merge!(blacklight_config.default_document_solr_params).reverse_merge!(@other_params)
15
+ end
16
+
17
+ def add_qt(request)
18
+ request[:qt] ||= blacklight_config.document_solr_request_handler if blacklight_config.document_solr_request_handler
19
+ end
20
+
21
+ def add_unique_id(request)
22
+ request[blacklight_config.document_unique_id_param] = @id
23
+ end
24
+ end
25
+ end
@@ -29,6 +29,13 @@ class <%= controller_name.classify %>Controller < ApplicationController
29
29
  #
30
30
  ## Should the raw solr document endpoint (e.g. /catalog/:id/raw) be enabled
31
31
  # config.raw_endpoint.enabled = false
32
+ #
33
+ ## Should advanced search be enabled
34
+ # config.advanced_search.enabled = true
35
+ #
36
+ ## Optional fine-tuning for advanced search, e.g., set different limits for
37
+ ## different facets.
38
+ # config.advanced_search.form_solr_parameters = {}
32
39
 
33
40
  ## Default parameters to send to solr for all search-like requests. See also SearchBuilder#processed_parameters
34
41
  config.default_solr_params = {
@@ -38,7 +45,7 @@ class <%= controller_name.classify %>Controller < ApplicationController
38
45
  # solr path which will be added to solr base url before the other solr params.
39
46
  #config.solr_path = 'select'
40
47
  #config.document_solr_path = 'get'
41
- #config.json_solr_path = 'advanced'
48
+ #config.json_solr_path = 'select'
42
49
 
43
50
  # items to show per page, each number in the array represent another option to choose from.
44
51
  #config.per_page = [10,20,50,100]
@@ -105,6 +112,12 @@ class <%= controller_name.classify %>Controller < ApplicationController
105
112
  # :show may be set to false if you don't want the facet to be drawn in the
106
113
  # facet bar
107
114
  #
115
+ # Set :include_in_advanced_search to false for any search field or facet field
116
+ # that you want to exclude from appearing in the advanced search page.
117
+ #
118
+ # Set :include_in_simple_select to false for any search field you want to render
119
+ # in the Advanced Search page but exclude from the main search box scope selector.
120
+ #
108
121
  # Set :index_range to true if you want the facet pagination view to have facet prefix-based navigation.
109
122
  # (useful when user clicks "more" on a large facet and wants to navigate alphabetically across a large set of results)
110
123
  # :index_range can be an array or range of prefixes that will be used to create the navigation (note: It is case sensitive when searching values)
@@ -121,7 +134,9 @@ class <%= controller_name.classify %>Controller < ApplicationController
121
134
 
122
135
  config.add_facet_field 'example_pivot_field',
123
136
  label: 'Pivot Field',
124
- pivot: ['language_ssim', 'subject_geo_ssim', 'subject_ssim'], collapsing: true
137
+ pivot: ['language_ssim', 'subject_geo_ssim', 'subject_ssim'],
138
+ collapsing: true,
139
+ include_in_advanced_search: false
125
140
 
126
141
  config.add_facet_field 'example_query_facet_field', label: 'Publish Date', :query => {
127
142
  :years_5 => { label: 'within 5 Years', fq: "pub_date_ssim:[#{Time.zone.now.year - 5 } TO *]" },
@@ -165,7 +180,7 @@ class <%= controller_name.classify %>Controller < ApplicationController
165
180
  config.add_show_field 'isbn_ssim', label: 'ISBN'
166
181
 
167
182
  # "fielded" search configuration. Used by pulldown among other places.
168
- # For supported keys in hash, see rdoc for Blacklight::SearchFields
183
+ # For supported keys in hash, see rdoc for Blacklight::Configuration::SearchField
169
184
  #
170
185
  # Search fields will inherit the :qt solr request handler from
171
186
  # config[:default_solr_parameters], OR can specify a different one
@@ -208,7 +223,7 @@ class <%= controller_name.classify %>Controller < ApplicationController
208
223
 
209
224
  # Specifying a :qt only to show it's possible, and so our internal automated
210
225
  # tests can test it. In this case it's the same as
211
- # config[:default_solr_parameters][:qt], so isn't actually neccesary.
226
+ # config[:default_solr_parameters][:qt], so isn't actually necessary.
212
227
  config.add_search_field('subject') do |field|
213
228
  field.qt = 'search'
214
229
  field.solr_parameters = {
@@ -218,6 +233,13 @@ class <%= controller_name.classify %>Controller < ApplicationController
218
233
  }
219
234
  end
220
235
 
236
+ # Set up a default advanced search configuration by using the current
237
+ # search_fields and facet_fields configs.
238
+ if config.advanced_search.enabled
239
+ config.copy_search_field_config_to_advanced!
240
+ config.copy_facet_field_config_to_advanced!
241
+ end
242
+
221
243
  # "sort results by" select (pulldown)
222
244
  # label in pulldown is followed by the name of the Solr field to sort by and
223
245
  # whether the sort is ascending or descending (it must be asc or desc