blacklight 8.7.0 → 8.8.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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/.env +1 -1
  3. data/.rubocop.yml +1 -0
  4. data/VERSION +1 -1
  5. data/app/assets/javascripts/blacklight/blacklight.esm.js +108 -4
  6. data/app/assets/javascripts/blacklight/blacklight.esm.js.map +1 -1
  7. data/app/assets/javascripts/blacklight/blacklight.js +108 -4
  8. data/app/assets/javascripts/blacklight/blacklight.js.map +1 -1
  9. data/app/assets/stylesheets/blacklight/_bootstrap_overrides.scss +2 -1
  10. data/app/assets/stylesheets/blacklight/_constraints.scss +0 -7
  11. data/app/assets/stylesheets/blacklight/_facets.scss +15 -14
  12. data/app/components/blacklight/response/facet_group_component.html.erb +1 -1
  13. data/app/components/blacklight/response/view_type_button_component.html.erb +1 -1
  14. data/app/components/blacklight/response/view_type_button_component.rb +6 -0
  15. data/app/components/blacklight/search/facet_suggest_input.html.erb +9 -0
  16. data/app/components/blacklight/search/facet_suggest_input.rb +20 -0
  17. data/app/components/blacklight/skip_link_component.html.erb +1 -1
  18. data/app/controllers/concerns/blacklight/catalog.rb +7 -1
  19. data/app/javascript/blacklight/debounce.js +15 -0
  20. data/app/javascript/blacklight/facet_suggest.js +26 -0
  21. data/app/javascript/blacklight/index.js +4 -0
  22. data/app/javascript/blacklight/modal.js +6 -5
  23. data/app/presenters/blacklight/facet_field_presenter.rb +2 -1
  24. data/app/services/blacklight/search_service.rb +5 -0
  25. data/app/views/catalog/facet.html.erb +1 -0
  26. data/app/views/catalog/facet_values.erb +3 -0
  27. data/app/views/kaminari/blacklight/_paginator.html.erb +2 -2
  28. data/app/views/layouts/catalog_result.html.erb +2 -2
  29. data/blacklight.gemspec +1 -0
  30. data/config/locales/blacklight.ar.yml +7 -0
  31. data/config/locales/blacklight.de.yml +7 -0
  32. data/config/locales/blacklight.en.yml +7 -0
  33. data/config/locales/blacklight.es.yml +7 -0
  34. data/config/locales/blacklight.fr.yml +7 -0
  35. data/config/locales/blacklight.hu.yml +7 -0
  36. data/config/locales/blacklight.it.yml +7 -0
  37. data/config/locales/blacklight.nl.yml +7 -0
  38. data/config/locales/blacklight.pt-BR.yml +7 -0
  39. data/config/locales/blacklight.sq.yml +7 -0
  40. data/config/locales/blacklight.zh.yml +7 -0
  41. data/lib/blacklight/configuration.rb +2 -1
  42. data/lib/blacklight/routes/searchable.rb +1 -0
  43. data/lib/blacklight/search_builder.rb +13 -0
  44. data/lib/blacklight/solr/response/facets.rb +1 -1
  45. data/lib/blacklight/solr/search_builder_behavior.rb +9 -1
  46. data/package.json +1 -1
  47. data/spec/components/blacklight/search/facet_suggest_input_spec.rb +49 -0
  48. data/spec/features/facets_spec.rb +21 -0
  49. data/spec/models/blacklight/search_builder_spec.rb +10 -0
  50. data/spec/models/blacklight/solr/response_spec.rb +18 -0
  51. data/spec/models/blacklight/solr/search_builder_behavior_spec.rb +64 -0
  52. data/spec/presenters/blacklight/facet_field_presenter_spec.rb +11 -1
  53. metadata +24 -3
@@ -1,9 +1,10 @@
1
1
  // Facet field headings and buttons
2
2
  .facet-field-heading {
3
+ --bl-facet-field-heading-font-weight: #{$headings-font-weight};
3
4
  border-bottom: 0;
4
5
 
5
6
  button {
6
- font-weight: $headings-font-weight;
7
+ font-weight: var(--bl-facet-field-heading-font-weight);
7
8
 
8
9
  &::after {
9
10
  content: "❯";
@@ -29,13 +29,6 @@
29
29
  @media (min-width: breakpoint-min(lg)) {
30
30
  max-width: breakpoint-min(lg) * 0.5;
31
31
  }
32
-
33
- &:hover,
34
- &:active {
35
- background-color: $secondary;
36
- border-color: $secondary;
37
- box-shadow: none;
38
- }
39
32
  }
40
33
 
41
34
  .filter-name:after {
@@ -3,6 +3,8 @@
3
3
  --bl-facet-active-item-color: #{$facet-active-item-color};
4
4
  --bl-facet-margin-bottom: #{$spacer};
5
5
  --bl-facet-remove-color: var(--bs-secondary-color);
6
+ --bl-facet-label-indent: -15px;
7
+ --bl-facet-label-padding-left: 15px;
6
8
 
7
9
  --bl-facet-limit-body-padding: #{$spacer};
8
10
 
@@ -12,18 +14,7 @@
12
14
  --bl-facets-smallish-margin-bottom: #{$spacer};
13
15
  --bl-facets-smallish-border-radius: #{$border-radius};
14
16
 
15
- .navbar-toggler {
16
- --bs-navbar-toggler-padding-x: #{$navbar-toggler-padding-x};
17
- --bs-navbar-toggler-padding-y: #{$navbar-toggler-padding-y};
18
- --bs-navbar-toggler-border-color: #{$navbar-light-toggler-border-color};
19
- --bs-navbar-toggler-border-radius: #{$navbar-toggler-border-radius};
20
- color: $navbar-light-active-color;
21
-
22
- &:hover,
23
- &:focus {
24
- color: $navbar-light-active-color;
25
- }
26
-
17
+ .facet-toggle-button {
27
18
  [data-hide-label] {
28
19
  display: inline;
29
20
  }
@@ -112,6 +103,16 @@
112
103
  .card-body {
113
104
  padding: var(--bl-facet-limit-body-padding);
114
105
  }
106
+
107
+ /* Provide a focus ring on the expand/collapse button */
108
+ .btn {
109
+ --bs-btn-focus-shadow-rgb: 50, 50, 50;
110
+ &:focus-visible {
111
+ border-color: var(--bs-btn-hover-border-color);
112
+ outline: 0;
113
+ box-shadow: var(--bs-btn-focus-box-shadow);
114
+ }
115
+ }
115
116
  }
116
117
 
117
118
  .facet-limit-active {
@@ -168,9 +169,9 @@
168
169
  .facet-label {
169
170
  hyphens: auto;
170
171
  overflow-wrap: break-word;
171
- padding-left: 15px;
172
+ padding-left: var(--bl-facet-label-padding-left);
172
173
  padding-right: 1em;
173
- text-indent: -15px;
174
+ text-indent: var(--bl-facet-label-indent);
174
175
  }
175
176
 
176
177
  .facet-count {
@@ -4,7 +4,7 @@
4
4
  <%= content_tag :h2, @title, class: 'facets-heading' if @title %>
5
5
 
6
6
  <%= content_tag :button,
7
- class:'navbar-toggler navbar-toggler-right',
7
+ class: 'btn btn-outline-secondary facet-toggle-button d-block d-lg-none',
8
8
  type: 'button',
9
9
  data: {
10
10
  toggle: 'collapse',
@@ -1,4 +1,4 @@
1
- <%= link_to url, title: label, class: "#{Array(@classes).join(' ')} view-type-#{ @key.to_s.parameterize } #{"active" if selected?}" do %>
1
+ <%= link_to url, title: label, aria: aria_attributes, class: "#{Array(@classes).join(' ')} view-type-#{ @key.to_s.parameterize } #{"active" if selected?}" do %>
2
2
  <%= icon %>
3
3
  <span class="caption"><%= label %></span>
4
4
  <% end %>
@@ -25,6 +25,12 @@ module Blacklight
25
25
  @view.display_label
26
26
  end
27
27
 
28
+ def aria_attributes
29
+ return unless selected?
30
+
31
+ { current: true }
32
+ end
33
+
28
34
  def url
29
35
  helpers.url_for(@search_state.to_h.merge(view: @key))
30
36
  end
@@ -0,0 +1,9 @@
1
+ <label for="facet_suggest_<%= facet.key %>">
2
+ <%= I18n.t('blacklight.search.facets.suggest.label', field_label: presenter&.label) %>
3
+ </label>
4
+ <%= text_field_tag "facet_suggest_#{facet.key}",
5
+ nil,
6
+ class: "facet-suggest form-control",
7
+ data: {facet_field: facet.key},
8
+ placeholder: I18n.t('blacklight.search.form.search.placeholder')
9
+ %>
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Blacklight
4
+ module Search
5
+ class FacetSuggestInput < Blacklight::Component
6
+ def initialize(facet:, presenter:)
7
+ @facet = facet
8
+ @presenter = presenter
9
+ end
10
+
11
+ private
12
+
13
+ attr_accessor :facet, :presenter
14
+
15
+ def render?
16
+ facet&.suggest
17
+ end
18
+ end
19
+ end
20
+ end
@@ -1,4 +1,4 @@
1
- <nav id="skip-link" role="navigation" class="visually-hidden-focusable sr-only sr-only-focusable" aria-label="<%= t('blacklight.skip_links.label') %>">
1
+ <nav id="skip-link" class="visually-hidden-focusable sr-only sr-only-focusable" aria-label="<%= t('blacklight.skip_links.label') %>">
2
2
  <div class="container-xl">
3
3
  <%= link_to_main %>
4
4
  <%= link_to_search %>
@@ -83,7 +83,11 @@ module Blacklight::Catalog
83
83
  @facet = blacklight_config.facet_fields[params[:id]]
84
84
  raise ActionController::RoutingError, 'Not Found' unless @facet
85
85
 
86
- @response = search_service.facet_field_response(@facet.key)
86
+ @response = if params[:query_fragment].present?
87
+ search_service.facet_suggest_response(@facet.key, params[:query_fragment])
88
+ else
89
+ search_service.facet_field_response(@facet.key)
90
+ end
87
91
  @display_facet = @response.aggregations[@facet.field]
88
92
 
89
93
  @presenter = @facet.presenter.new(@facet, @display_facet, view_context)
@@ -92,6 +96,8 @@ module Blacklight::Catalog
92
96
  format.html do
93
97
  # Draw the partial for the "more" facet modal window:
94
98
  return render layout: false if request.xhr?
99
+ # Only show the facet names and their values:
100
+ return render 'facet_values', layout: false if params[:only_values]
95
101
  # Otherwise draw the facet selector for users who have javascript disabled.
96
102
  end
97
103
  format.json
@@ -0,0 +1,15 @@
1
+ // Usage:
2
+ // ```
3
+ // const basicFunction = (entry) => console.log(entry)
4
+ // const debounced = debounce(basicFunction("I should only be called once"));
5
+ //
6
+ // debounced // does NOT print to the screen because it is invoked again less than 200 milliseconds later
7
+ // debounced // does print to the screen
8
+ // ```
9
+ export default function debounce(func, timeout = 200) {
10
+ let timer;
11
+ return (...args) => {
12
+ clearTimeout(timer);
13
+ timer = setTimeout(() => { func.apply(this, args); }, timeout);
14
+ };
15
+ }
@@ -0,0 +1,26 @@
1
+ import debounce from "blacklight/debounce";
2
+
3
+ const FacetSuggest = async (e) => {
4
+ if (e.target.matches('.facet-suggest')) {
5
+ const queryFragment = e.target.value?.trim();
6
+ const facetField = e.target.dataset.facetField;
7
+ if (!facetField) { return; }
8
+
9
+ const urlToFetch = `/catalog/facet_suggest/${facetField}/${queryFragment}`
10
+ const response = await fetch(urlToFetch);
11
+ if (response.ok) {
12
+ const blob = await response.blob()
13
+ const text = await blob.text()
14
+
15
+ const facetArea = document.querySelector('.facet-extended-list');
16
+
17
+ if (text && facetArea) {
18
+ facetArea.innerHTML = text
19
+ }
20
+ }
21
+ }
22
+ };
23
+
24
+ document.addEventListener('input', debounce(FacetSuggest));
25
+
26
+ export default FacetSuggest
@@ -1,13 +1,17 @@
1
1
  import BookmarkToggle from 'blacklight/bookmark_toggle'
2
2
  import ButtonFocus from 'blacklight/button_focus'
3
+ import FacetSuggest from 'blacklight/facet_suggest'
3
4
  import Modal from 'blacklight/modal'
5
+ import ModalForm from 'blacklight/modalForm'
4
6
  import SearchContext from 'blacklight/search_context'
5
7
  import Core from 'blacklight/core'
6
8
 
7
9
  export default {
8
10
  BookmarkToggle,
9
11
  ButtonFocus,
12
+ FacetSuggest,
10
13
  Modal,
14
+ ModalForm,
11
15
  SearchContext,
12
16
  Core,
13
17
  onLoad: Core.onLoad
@@ -52,7 +52,6 @@
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'
56
55
 
57
56
  const Modal = (() => {
58
57
  const modal = {}
@@ -149,13 +148,15 @@ const Modal = (() => {
149
148
  };
150
149
 
151
150
  modal.setupModal = function() {
152
- // Register both trigger and preserve selectors in ONE event handler, combining
153
- // into one selector with a comma, so if something matches BOTH selectors, it
154
- // still only gets the event handler called once.
151
+ // Register several click handlers in ONE event handler for efficiency
152
+ //
153
+ // * close button OR click on backdrop (modal.modalSelector) closes modal
154
+ // * trigger and preserve link in modal functionality -- if somethign matches both trigger and
155
+ // preserve, still only called once.
155
156
  document.addEventListener('click', (e) => {
156
157
  if (e.target.closest(`${modal.triggerLinkSelector}, ${modal.preserveLinkSelector}`))
157
158
  modal.modalAjaxLinkClick(e)
158
- else if (e.target.closest('[data-bl-dismiss="modal"]'))
159
+ else if (e.target.matches(`${modal.modalSelector}`) || e.target.closest('[data-bl-dismiss="modal"]'))
159
160
  modal.hide()
160
161
  })
161
162
  };
@@ -31,7 +31,8 @@ module Blacklight
31
31
  end
32
32
 
33
33
  def in_modal?
34
- search_state.params[:action] == "facet"
34
+ modal_like_actions = %w[facet facet_suggest]
35
+ modal_like_actions.include? search_state.params[:action]
35
36
  end
36
37
 
37
38
  def modal_path
@@ -62,6 +62,11 @@ module Blacklight
62
62
  repository.search(query.merge(extra_controller_params))
63
63
  end
64
64
 
65
+ def facet_suggest_response(facet_field, facet_suggestion_query, extra_controller_params = {})
66
+ query = search_builder.with(search_state).facet(facet_field).facet_suggestion_query(facet_suggestion_query)
67
+ repository.search(query.merge(extra_controller_params))
68
+ end
69
+
65
70
  # Get the previous and next document from a search result
66
71
  # @return [Blacklight::Solr::Response, Array<Blacklight::SolrDocument>] the solr response and a list of the first and last document
67
72
  def previous_and_next_documents_for_search(index, request_params, extra_controller_params = {})
@@ -6,6 +6,7 @@
6
6
  <% end %>
7
7
 
8
8
  <% component.with_title { facet_field_label(@facet.key) } %>
9
+ <%= render Blacklight::Search::FacetSuggestInput.new(facet: @facet, presenter: @presenter) %>
9
10
 
10
11
  <%= render partial: 'facet_index_navigation' if @facet.index_range && @display_facet.index? %>
11
12
 
@@ -0,0 +1,3 @@
1
+ <%= render Blacklight::FacetComponent.new(display_facet: @display_facet,
2
+ blacklight_config: blacklight_config,
3
+ layout: false) %>
@@ -11,7 +11,7 @@
11
11
  <%= paginator.render do -%>
12
12
  <ul class="pagination">
13
13
  <%= prev_page_tag %>
14
- <%= next_page_tag if Blacklight::Engine.config.blacklight.paginator[:next_page_position] == :before %>
14
+ <%= next_page_tag if Blacklight::Engine.config.blacklight.paginator[:next_button_position] == :before %>
15
15
  <% each_relevant_page do |page| -%>
16
16
  <% if page.left_outer? || page.right_outer? || page.inside_window? -%>
17
17
  <%= page_tag page %>
@@ -19,6 +19,6 @@
19
19
  <%= gap_tag %>
20
20
  <% end -%>
21
21
  <% end -%>
22
- <%= next_page_tag if Blacklight::Engine.config.blacklight.paginator[:next_page_position] == :after %>
22
+ <%= next_page_tag if Blacklight::Engine.config.blacklight.paginator[:next_button_position] == :after %>
23
23
  </ul>
24
24
  <% end -%>
@@ -3,9 +3,9 @@
3
3
  <%= yield %>
4
4
  </section>
5
5
 
6
- <section class="<%= show_sidebar_classes %>">
6
+ <aside class="<%= show_sidebar_classes %>" aria-label="<%= t('.aria.sidebar') %>">
7
7
  <%= content_for(:sidebar) %>
8
- </section>
8
+ </aside>
9
9
  <% end %>
10
10
 
11
11
  <%= render template: "layouts/blacklight/base" %>
data/blacklight.gemspec CHANGED
@@ -49,6 +49,7 @@ Gem::Specification.new do |s|
49
49
  s.add_development_dependency "rubocop-capybara"
50
50
  s.add_development_dependency "rubocop-rspec_rails"
51
51
  s.add_development_dependency "rubocop-factory_bot"
52
+ s.add_development_dependency "rspec-benchmark"
52
53
  s.add_development_dependency "i18n-tasks", '~> 1.0'
53
54
  s.add_development_dependency "solr_wrapper"
54
55
  end
@@ -111,6 +111,9 @@ ar:
111
111
  sort:
112
112
  count: ترتيب رقمي
113
113
  index: ترتيب أبجدي
114
+ suggest:
115
+ label: الفلتر %{field_label}
116
+ placeholder: فلتر...
114
117
  title: تحديد نطاق البحث
115
118
  filters:
116
119
  label: "%{label}:"
@@ -219,6 +222,10 @@ ar:
219
222
  aria:
220
223
  container_label: التنقل الرئيسي
221
224
  welcome: مرحبًا!
225
+ layouts:
226
+ catalog_result:
227
+ aria:
228
+ sidebar: أدوات
222
229
  views:
223
230
  pagination:
224
231
  aria:
@@ -102,6 +102,9 @@ de:
102
102
  sort:
103
103
  count: Numerisch ordnen
104
104
  index: A-Z Ordnen
105
+ suggest:
106
+ label: Filter %{field_label}
107
+ placeholder: Filter...
105
108
  title: Suche beschränken
106
109
  filters:
107
110
  label: "%{label}:"
@@ -206,6 +209,10 @@ de:
206
209
  aria:
207
210
  container_label: Hauptnavigation
208
211
  welcome: Willkommen!
212
+ layouts:
213
+ catalog_result:
214
+ aria:
215
+ sidebar: Werkzeuge
209
216
  views:
210
217
  pagination:
211
218
  aria:
@@ -120,6 +120,9 @@ en:
120
120
  sort:
121
121
  count: Numerical Sort
122
122
  index: A-Z Sort
123
+ suggest:
124
+ label: "Filter %{field_label}"
125
+ placeholder: Filter...
123
126
  title: Limit your search
124
127
  filters:
125
128
  label: "%{label}:"
@@ -242,3 +245,7 @@ en:
242
245
  pagination_compact:
243
246
  next: Next &raquo;
244
247
  previous: "&laquo; Previous"
248
+ layouts:
249
+ catalog_result:
250
+ aria:
251
+ sidebar: Tools
@@ -101,6 +101,9 @@ es:
101
101
  sort:
102
102
  count: Ordenación numérica
103
103
  index: Ordenación A-Z
104
+ suggest:
105
+ label: Filtro %{field_label}
106
+ placeholder: Filtrar...
104
107
  title: Limite su búsqueda
105
108
  filters:
106
109
  label: "%{label}:"
@@ -205,6 +208,10 @@ es:
205
208
  aria:
206
209
  container_label: Navegación principal
207
210
  welcome: "¡Bienvenido!"
211
+ layouts:
212
+ catalog_result:
213
+ aria:
214
+ sidebar: Herramientas
208
215
  views:
209
216
  pagination:
210
217
  aria:
@@ -101,6 +101,9 @@ fr:
101
101
  sort:
102
102
  count: Du + au - fréquent
103
103
  index: Tri de A à Z
104
+ suggest:
105
+ label: Filtre %{field_label}
106
+ placeholder: Filtre...
104
107
  title: Limiter votre recherche
105
108
  filters:
106
109
  label: "%{label}:"
@@ -205,6 +208,10 @@ fr:
205
208
  aria:
206
209
  container_label: Navigation principale
207
210
  welcome: Welcome!
211
+ layouts:
212
+ catalog_result:
213
+ aria:
214
+ sidebar: Outils
208
215
  views:
209
216
  pagination:
210
217
  aria:
@@ -99,6 +99,9 @@ hu:
99
99
  sort:
100
100
  count: Numerikus rendezés
101
101
  index: A-Z rendezés
102
+ suggest:
103
+ label: Szűrő %{field_label}
104
+ placeholder: Szűrő...
102
105
  title: Szűrje tovább a keresését
103
106
  filters:
104
107
  label: "%{label}:"
@@ -203,6 +206,10 @@ hu:
203
206
  aria:
204
207
  container_label: Fő navigáció
205
208
  welcome: Üdvözöljük!
209
+ layouts:
210
+ catalog_result:
211
+ aria:
212
+ sidebar: Eszközök
206
213
  views:
207
214
  pagination:
208
215
  aria:
@@ -102,6 +102,9 @@ it:
102
102
  sort:
103
103
  count: Ordina per numero
104
104
  index: Ordina A-Z
105
+ suggest:
106
+ label: Filtro %{field_label}
107
+ placeholder: Filtro...
105
108
  title: Affina la ricerca
106
109
  filters:
107
110
  label: "%{label}:"
@@ -206,6 +209,10 @@ it:
206
209
  aria:
207
210
  container_label: Navigazione principale
208
211
  welcome: Benvenuti!
212
+ layouts:
213
+ catalog_result:
214
+ aria:
215
+ sidebar: Utensili
209
216
  views:
210
217
  pagination:
211
218
  aria:
@@ -99,6 +99,9 @@ nl:
99
99
  sort:
100
100
  count: Numeriek sorteren
101
101
  index: A-Z Sorteren
102
+ suggest:
103
+ label: Filteren %{field_label}
104
+ placeholder: Filter...
102
105
  title: Verfijn uw zoekopdracht
103
106
  filters:
104
107
  label: "%{label}:"
@@ -203,6 +206,10 @@ nl:
203
206
  aria:
204
207
  container_label: Hoofdnavigatie
205
208
  welcome: Welkom!
209
+ layouts:
210
+ catalog_result:
211
+ aria:
212
+ sidebar: Hulpmiddelen
206
213
  views:
207
214
  pagination:
208
215
  aria:
@@ -100,6 +100,9 @@ pt-BR:
100
100
  sort:
101
101
  count: Ordenar por Número
102
102
  index: Ordem Alfabética A-Z
103
+ suggest:
104
+ label: Filtro %{field_label}
105
+ placeholder: Filtro...
103
106
  title: Filtre sua busca
104
107
  filters:
105
108
  label: "%{label}:"
@@ -204,6 +207,10 @@ pt-BR:
204
207
  aria:
205
208
  container_label: Navegação principal
206
209
  welcome: Bem-Vindo!
210
+ layouts:
211
+ catalog_result:
212
+ aria:
213
+ sidebar: Ferramentas
207
214
  views:
208
215
  pagination:
209
216
  aria:
@@ -99,6 +99,9 @@ sq:
99
99
  sort:
100
100
  count: Renditja numerike
101
101
  index: A-Z Renditja
102
+ suggest:
103
+ label: Filtri %{field_label}
104
+ placeholder: Filtro...
102
105
  title: Kufizo këkimin
103
106
  filters:
104
107
  label: "%{label}:"
@@ -203,6 +206,10 @@ sq:
203
206
  aria:
204
207
  container_label: Lundrimi kryesor
205
208
  welcome: Mirësevini!
209
+ layouts:
210
+ catalog_result:
211
+ aria:
212
+ sidebar: Mjetet
206
213
  views:
207
214
  pagination:
208
215
  aria:
@@ -99,6 +99,9 @@ zh:
99
99
  sort:
100
100
  count: 按数量排序
101
101
  index: 按字母排序
102
+ suggest:
103
+ label: 过滤器 %{field_label}
104
+ placeholder: 筛选...
102
105
  title: 限定搜索
103
106
  filters:
104
107
  label: "%{label}:"
@@ -203,6 +206,10 @@ zh:
203
206
  aria:
204
207
  container_label: 主导航
205
208
  welcome: 欢迎!
209
+ layouts:
210
+ catalog_result:
211
+ aria:
212
+ sidebar: 工具
206
213
  views:
207
214
  pagination:
208
215
  aria:
@@ -35,7 +35,8 @@ module Blacklight
35
35
  end
36
36
  end
37
37
 
38
- BASIC_SEARCH_PARAMETERS = [:q, :qt, :page, :per_page, :search_field, :sort, :controller, :action, :'facet.page', :'facet.prefix', :'facet.sort', :rows, :format, :view].freeze
38
+ BASIC_SEARCH_PARAMETERS = [:q, :qt, :page, :per_page, :search_field, :sort, :controller, :action, :'facet.page', :'facet.prefix', :'facet.sort', :rows, :format, :view, :id, :facet_id,
39
+ :query_fragment, :only_values].freeze
39
40
  ADVANCED_SEARCH_PARAMETERS = [{ clause: {} }, :op].freeze
40
41
 
41
42
  # rubocop:disable Metrics/BlockLength
@@ -18,6 +18,7 @@ module Blacklight
18
18
  mapper.get "opensearch"
19
19
  mapper.get 'suggest', as: 'suggest_index'
20
20
  mapper.get "facet/:id", action: 'facet', as: 'facet'
21
+ mapper.get "facet_suggest/:id/(:query_fragment)", action: 'facet', as: 'facet_suggest', defaults: { only_values: true }
21
22
  end
22
23
  end
23
24
  end
@@ -224,6 +224,19 @@ module Blacklight
224
224
  @facet
225
225
  end
226
226
 
227
+ def facet_suggestion_query=(value)
228
+ params_will_change!
229
+ @facet_suggestion_query = value
230
+ end
231
+
232
+ def facet_suggestion_query(value = nil)
233
+ if value
234
+ self.facet_suggestion_query = value
235
+ return self
236
+ end
237
+ @facet_suggestion_query
238
+ end
239
+
227
240
  # Decode the user provided 'sort' parameter into a sort string that can be
228
241
  # passed to the search. This sanitizes the input by ensuring only
229
242
  # configured search values are passed through to the search.
@@ -157,7 +157,7 @@ module Blacklight::Solr::Response::Facets
157
157
  # facet data in the response
158
158
  def default_aggregations
159
159
  @default_aggregations ||= begin
160
- h = Hash.new { |key| null_facet_field_object(key) }
160
+ h = Hash.new { |_hash, key| null_facet_field_object(key) }
161
161
  h.with_indifferent_access
162
162
  end
163
163
  end
@@ -10,7 +10,8 @@ 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_facet_paging_to_solr, :add_adv_search_clauses,
13
+ :add_facet_paging_to_solr, :add_facet_suggestion_parameters,
14
+ :add_adv_search_clauses,
14
15
  :add_additional_filters
15
16
  ]
16
17
  end
@@ -276,6 +277,13 @@ module Blacklight::Solr
276
277
  solr_params[:"f.#{facet_config.field}.facet.prefix"] = prefix if prefix
277
278
  end
278
279
 
280
+ def add_facet_suggestion_parameters(solr_params)
281
+ return if facet.blank? || facet_suggestion_query.blank?
282
+
283
+ solr_params[:'facet.contains'] = facet_suggestion_query[0..50]
284
+ solr_params[:'facet.contains.ignoreCase'] = true
285
+ end
286
+
279
287
  def with_ex_local_param(ex, value)
280
288
  if ex
281
289
  "{!ex=#{ex}}#{value}"