blacklight 7.20.1 → 7.21.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 (38) hide show
  1. checksums.yaml +4 -4
  2. data/.babelrc +11 -0
  3. data/.github/workflows/ruby.yml +2 -2
  4. data/Gemfile +1 -1
  5. data/README.md +1 -1
  6. data/VERSION +1 -1
  7. data/app/assets/javascripts/blacklight/blacklight.js +41 -28
  8. data/app/assets/stylesheets/blacklight/_constraints.scss +1 -1
  9. data/app/assets/stylesheets/blacklight/_controls.scss +2 -1
  10. data/app/components/blacklight/constraints_component.rb +2 -6
  11. data/app/components/blacklight/system/modal_component.html.erb +2 -2
  12. data/app/controllers/concerns/blacklight/catalog.rb +2 -2
  13. data/app/javascript/blacklight/core.js +5 -1
  14. data/app/javascript/blacklight/modal.js +1 -1
  15. data/app/models/concerns/blacklight/document/email.rb +18 -6
  16. data/app/models/concerns/blacklight/document/sms.rb +16 -4
  17. data/app/models/record_mailer.rb +9 -1
  18. data/app/presenters/blacklight/facet_item_presenter.rb +2 -0
  19. data/app/views/record_mailer/sms_record.text.erb +1 -1
  20. data/config/locales/blacklight.de.yml +1 -1
  21. data/lib/blacklight/configuration.rb +9 -0
  22. data/lib/blacklight/engine.rb +2 -0
  23. data/lib/blacklight/search_state/filter_field.rb +34 -19
  24. data/lib/blacklight/solr/response/facets.rb +2 -1
  25. data/lib/blacklight/solr/search_builder_behavior.rb +2 -14
  26. data/package.json +3 -1
  27. data/spec/controllers/catalog_controller_spec.rb +14 -2
  28. data/spec/features/axe_spec.rb +6 -7
  29. data/spec/features/facet_missing_spec.rb +12 -4
  30. data/spec/lib/blacklight/search_state/filter_field_spec.rb +3 -17
  31. data/spec/models/blacklight/configuration_spec.rb +92 -0
  32. data/spec/models/blacklight/document/email_spec.rb +32 -0
  33. data/spec/models/blacklight/document/sms_spec.rb +33 -0
  34. data/spec/models/blacklight/solr/response/facets_spec.rb +1 -1
  35. data/spec/models/blacklight/solr/search_builder_spec.rb +0 -13
  36. data/spec/models/record_mailer_spec.rb +30 -2
  37. data/spec/spec_helper.rb +3 -3
  38. metadata +7 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ee4c46b8533bb359a6619ef6dddd96b4de1449b4bfc96db65a357469bebc7cc1
4
- data.tar.gz: 9eecbab00d1484a3e417bd60245479fc58d6bd9c41a7b16be91d3cef056846a2
3
+ metadata.gz: 8f9ecb2c98805e0783286a52510875f35da4b19983fa3c9f174fcce921d2b630
4
+ data.tar.gz: 221bbc331cace14c9212c4be38d372b3a62b15fa5d16af116f79e90c53a5dafe
5
5
  SHA512:
6
- metadata.gz: 97d968403618ee1d25fac527cea64467e3be78040e0d58e8d672463b94c22f272ff7b30fec66af576084bf2a9e8d169a7d3bec9b58b0d1187bb8ffc5bdab2f21
7
- data.tar.gz: 31855c12d2d58eb7863aa90a4b60c106d208b302460bd0f263fdd32baf8d6025f94025cdf953c82a42220a403c2d0eeae367e7729c7f714f8bc19d23bb561974
6
+ metadata.gz: ebee61b6584dbf10836b754f3f390acc24dce35da380caf633986bd1792991aaec3c07b9299f0f32beed54e339eaec4e0051f2350c08b2111e855688665bf4d4
7
+ data.tar.gz: 251aca6a6d0908be8a3b75312bd1604e88b4a55810f3553b6634f281ecd79b176ac2ef04797e3a02f42f41c8eaec0d49d734f10a699f8a739c17a65a5cf515ca
data/.babelrc ADDED
@@ -0,0 +1,11 @@
1
+ {
2
+ "presets": [
3
+ [
4
+ "@babel/preset-env",
5
+ {
6
+ "useBuiltIns": "entry",
7
+ "corejs": "2.0"
8
+ }
9
+ ]
10
+ ]
11
+ }
@@ -9,9 +9,9 @@ name: CI
9
9
 
10
10
  on:
11
11
  push:
12
- branches: [ master ]
12
+ branches: [ main ]
13
13
  pull_request:
14
- branches: [ master ]
14
+ branches: [ main ]
15
15
 
16
16
  jobs:
17
17
  lint:
data/Gemfile CHANGED
@@ -27,7 +27,7 @@ else
27
27
  if ENV['RAILS_VERSION']
28
28
  if ENV['RAILS_VERSION'] == 'edge'
29
29
  gem 'rails', github: 'rails/rails'
30
- ENV['ENGINE_CART_RAILS_OPTIONS'] = '--edge --skip-turbolinks'
30
+ ENV['ENGINE_CART_RAILS_OPTIONS'] = '--edge'
31
31
  else
32
32
  gem 'rails', ENV['RAILS_VERSION']
33
33
  end
data/README.md CHANGED
@@ -39,7 +39,7 @@ rails generate blacklight:install
39
39
 
40
40
  ## Contributing Code
41
41
 
42
- Code contributions are always welcome, instructions for contributing can be found at [CONTRIBUTING.md](https://github.com/projectblacklight/blacklight/blob/master/CONTRIBUTING.md).
42
+ Code contributions are always welcome, instructions for contributing can be found at [CONTRIBUTING.md](https://github.com/projectblacklight/blacklight/blob/main/CONTRIBUTING.md).
43
43
 
44
44
  ## Configuring Apache Solr
45
45
  You'll also want some information about how Blacklight expects [Apache Solr](http://lucene.apache.org/solr ) to run, which you can find in [README_SOLR](https://github.com/projectblacklight/blacklight/wiki/README_SOLR)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 7.20.1
1
+ 7.21.0
@@ -1,18 +1,22 @@
1
+ "use strict";
2
+
1
3
  Blacklight = function () {
2
4
  var buffer = new Array();
3
5
  return {
4
- onLoad: function (func) {
6
+ onLoad: function onLoad(func) {
5
7
  buffer.push(func);
6
8
  },
7
- activate: function () {
9
+ activate: function activate() {
8
10
  for (var i = 0; i < buffer.length; i++) {
9
11
  buffer[i].call();
10
12
  }
11
13
  },
12
- listeners: function () {
14
+ listeners: function listeners() {
13
15
  var listeners = [];
14
16
 
15
- if (typeof Turbolinks !== 'undefined' && Turbolinks.supported) {
17
+ if (typeof Turbo !== 'undefined') {
18
+ listeners.push('turbo:load');
19
+ } else if (typeof Turbolinks !== 'undefined' && Turbolinks.supported) {
16
20
  // Turbolinks 5
17
21
  if (Turbolinks.BrowserAdapter) {
18
22
  listeners.push('turbolinks:load');
@@ -37,7 +41,9 @@ Blacklight.listeners().forEach(function (listener) {
37
41
  });
38
42
  });
39
43
  Blacklight.onLoad(function () {
40
- const elem = document.querySelector('.no-js');
44
+ var elem = document.querySelector('.no-js'); // The "no-js" class may already have been removed because this function is
45
+ // run on every turbo:load event, in that case, it won't find an element.
46
+
41
47
  if (!elem) return;
42
48
  elem.classList.remove('no-js');
43
49
  elem.classList.add('js');
@@ -87,7 +93,7 @@ Blacklight.onLoad(function () {
87
93
  $(Blacklight.doBookmarkToggleBehavior.selector).blCheckboxSubmit({
88
94
  // cssClass is added to elements added, plus used for id base
89
95
  cssClass: 'toggle-bookmark',
90
- success: function (checked, response) {
96
+ success: function success(checked, response) {
91
97
  if (response.bookmarks) {
92
98
  $('[data-role=bookmark-counter]').text(response.bookmarks.count);
93
99
  }
@@ -105,8 +111,8 @@ Blacklight.onLoad(function () {
105
111
  // Button clicks should change focus. As of 10/3/19, Firefox for Mac and
106
112
  // Safari both do not set focus to a button on button click.
107
113
  // See https://zellwk.com/blog/inconsistent-button-behavior/ for background information
108
- document.querySelectorAll('button.collapse-toggle').forEach(button => {
109
- button.addEventListener('click', () => {
114
+ document.querySelectorAll('button.collapse-toggle').forEach(function (button) {
115
+ button.addEventListener('click', function () {
110
116
  event.target.focus();
111
117
  });
112
118
  });
@@ -193,12 +199,12 @@ Blacklight.onLoad(function () {
193
199
  dataType: 'json',
194
200
  type: form.attr('method').toUpperCase(),
195
201
  data: form.serialize(),
196
- error: function () {
202
+ error: function error() {
197
203
  label.removeAttr('disabled');
198
204
  checkbox.removeAttr('disabled');
199
205
  options.error.call();
200
206
  },
201
- success: function (data, status, xhr) {
207
+ success: function success(data, status, xhr) {
202
208
  //if app isn't running at all, xhr annoyingly
203
209
  //reports success with status 0.
204
210
  if (xhr.status != 0) {
@@ -224,10 +230,10 @@ Blacklight.onLoad(function () {
224
230
  $.fn.blCheckboxSubmit.defaults = {
225
231
  //cssClass is added to elements added, plus used for id base
226
232
  cssClass: 'blCheckboxSubmit',
227
- error: function () {
233
+ error: function error() {
228
234
  alert("Error");
229
235
  },
230
- success: function () {} //callback
236
+ success: function success() {} //callback
231
237
 
232
238
  };
233
239
  })(jQuery);
@@ -243,12 +249,12 @@ Blacklight.doResizeFacetLabelsAndCounts = function () {
243
249
  }
244
250
 
245
251
  document.querySelectorAll('.facet-values, .pivot-facet').forEach(function (elem) {
246
- const nodes = elem.querySelectorAll('.facet-count'); // TODO: when we drop ie11 support, this can become the spread operator:
252
+ var nodes = elem.querySelectorAll('.facet-count'); // TODO: when we drop ie11 support, this can become the spread operator:
247
253
 
248
- const longest = Array.from(nodes).sort(longer)[0];
254
+ var longest = Array.from(nodes).sort(longer)[0];
249
255
 
250
256
  if (longest && longest.textContent) {
251
- const width = longest.textContent.length + 1 + 'ch';
257
+ var width = longest.textContent.length + 1 + 'ch';
252
258
  elem.querySelector('.facet-count').style.width = width;
253
259
  }
254
260
  });
@@ -365,7 +371,7 @@ Blacklight.modal.onFailure = function (jqXHR, textStatus, errorThrown) {
365
371
  Blacklight.modal.receiveAjax = function (contents) {
366
372
  // does it have a data- selector for container?
367
373
  // important we don't execute script tags, we shouldn't.
368
- // code modelled off of JQuery ajax.load. https://github.com/jquery/jquery/blob/master/src/ajax/load.js?source=c#L62
374
+ // code modelled off of JQuery ajax.load. https://github.com/jquery/jquery/blob/main/src/ajax/load.js?source=c#L62
369
375
  var container = $('<div>').append(jQuery.parseHTML(contents)).find(Blacklight.modal.containerSelector).first();
370
376
 
371
377
  if (container.length !== 0) {
@@ -443,9 +449,9 @@ Blacklight.doSearchContextBehavior = function () {
443
449
  return Blacklight.do_search_context_behavior();
444
450
  }
445
451
 
446
- const elements = document.querySelectorAll('a[data-context-href]'); // Equivalent to Array.from(), but supports ie11
452
+ var elements = document.querySelectorAll('a[data-context-href]'); // Equivalent to Array.from(), but supports ie11
447
453
 
448
- const nodes = Array.prototype.slice.call(elements);
454
+ var nodes = Array.prototype.slice.call(elements);
449
455
  nodes.forEach(function (element) {
450
456
  element.addEventListener('click', function (e) {
451
457
  Blacklight.handleSearchContextMethod.call(e.currentTarget, e);
@@ -453,9 +459,17 @@ Blacklight.doSearchContextBehavior = function () {
453
459
  });
454
460
  };
455
461
 
456
- Blacklight.csrfToken = () => document.querySelector('meta[name=csrf-token]')?.content;
462
+ Blacklight.csrfToken = function () {
463
+ var _document$querySelect;
464
+
465
+ return (_document$querySelect = document.querySelector('meta[name=csrf-token]')) === null || _document$querySelect === void 0 ? void 0 : _document$querySelect.content;
466
+ };
467
+
468
+ Blacklight.csrfParam = function () {
469
+ var _document$querySelect2;
457
470
 
458
- Blacklight.csrfParam = () => document.querySelector('meta[name=csrf-param]')?.content; // this is the Rails.handleMethod with a couple adjustments, described inline:
471
+ return (_document$querySelect2 = document.querySelector('meta[name=csrf-param]')) === null || _document$querySelect2 === void 0 ? void 0 : _document$querySelect2.content;
472
+ }; // this is the Rails.handleMethod with a couple adjustments, described inline:
459
473
  // first, we're attaching this directly to the event handler, so we can check for meta-keys
460
474
 
461
475
 
@@ -467,22 +481,21 @@ Blacklight.handleSearchContextMethod = function (event) {
467
481
 
468
482
  var link = this; // instead of using the normal href, we need to use the context href instead
469
483
 
470
- let href = link.getAttribute('data-context-href');
471
- let target = link.getAttribute('target');
472
- let csrfToken = Blacklight.csrfToken();
473
- let csrfParam = Blacklight.csrfParam();
474
- let form = document.createElement('form');
484
+ var href = link.getAttribute('data-context-href');
485
+ var target = link.getAttribute('target');
486
+ var csrfToken = Blacklight.csrfToken();
487
+ var csrfParam = Blacklight.csrfParam();
488
+ var form = document.createElement('form');
475
489
  form.method = 'post';
476
490
  form.action = href;
477
- let formContent = `<input name="_method" value="post" type="hidden" />
478
- <input name="redirect" value="${link.getAttribute('href')}" type="hidden" />`; // check for meta keys.. if set, we should open in a new tab
491
+ var formContent = "<input name=\"_method\" value=\"post\" type=\"hidden\" />\n <input name=\"redirect\" value=\"".concat(link.getAttribute('href'), "\" type=\"hidden\" />"); // check for meta keys.. if set, we should open in a new tab
479
492
 
480
493
  if (event.metaKey || event.ctrlKey) {
481
494
  target = '_blank';
482
495
  }
483
496
 
484
497
  if (csrfParam !== undefined && csrfToken !== undefined) {
485
- formContent += `<input name="${csrfParam}" value="${csrfToken}" type="hidden" />`;
498
+ formContent += "<input name=\"".concat(csrfParam, "\" value=\"").concat(csrfToken, "\" type=\"hidden\" />");
486
499
  } // Must trigger submit by click on a button, else "submit" event handler won't work!
487
500
  // https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/submit
488
501
 
@@ -1,6 +1,6 @@
1
1
  .constraints-container {
2
2
  @extend .mb-2;
3
- @extend .d-flex;
3
+ display: flex;
4
4
  }
5
5
 
6
6
  .applied-filter {
@@ -1,5 +1,6 @@
1
1
  .search-widgets {
2
- @extend .d-flex;
2
+ display: flex;
3
+
3
4
  > * {
4
5
  @extend .mx-1;
5
6
  }
@@ -63,14 +63,10 @@ module Blacklight
63
63
 
64
64
  Deprecation.silence(Blacklight::SearchState) do
65
65
  @search_state.filters.map do |facet|
66
- missing_facet = @search_state.params.dig("f", "-#{facet.key}:").present?
67
66
  facet.values.map do |val|
68
- next if val.blank? && !missing_facet
67
+ next if val.blank?
69
68
 
70
- if missing_facet && val.blank?
71
- missing = I18n.t("blacklight.search.facets.missing")
72
- yield facet_item_presenter(facet.config, missing, facet.key)
73
- elsif val.is_a?(Array)
69
+ if val.is_a?(Array)
74
70
  yield inclusive_facet_item_presenter(facet.config, val, facet.key) if val.any?(&:present?)
75
71
  else
76
72
  yield facet_item_presenter(facet.config, val, facet.key)
@@ -6,8 +6,8 @@
6
6
  <h1 class="modal-title"><%= title %></h1>
7
7
  <% end) %>
8
8
 
9
- <button type="button" class="blacklight-modal-close btn-close close" data-dismiss="modal" aria-label="<%= t('blacklight.modal.close') %>">
10
- <span aria-hidden="true">&times;</span>
9
+ <button type="button" class="blacklight-modal-close btn-close close" data-bs-dismiss="modal" data-dismiss="modal" aria-label="<%= t('blacklight.modal.close') %>">
10
+ <span aria-hidden="true" class="visually-hidden">&times;</span>
11
11
  </button>
12
12
  </div>
13
13
 
@@ -260,7 +260,7 @@ module Blacklight::Catalog
260
260
 
261
261
  # Email Action (this will render the appropriate view on GET requests and process the form and send the email on POST requests)
262
262
  def email_action documents
263
- mail = RecordMailer.email_record(documents, { to: params[:to], message: params[:message] }, url_options)
263
+ mail = RecordMailer.email_record(documents, { to: params[:to], message: params[:message], config: blacklight_config }, url_options)
264
264
  if mail.respond_to? :deliver_now
265
265
  mail.deliver_now
266
266
  else
@@ -271,7 +271,7 @@ module Blacklight::Catalog
271
271
  # SMS action (this will render the appropriate view on GET requests and process the form and send the email on POST requests)
272
272
  def sms_action documents
273
273
  to = "#{params[:to].gsub(/[^\d]/, '')}@#{params[:carrier]}"
274
- mail = RecordMailer.sms_record(documents, { to: to }, url_options)
274
+ mail = RecordMailer.sms_record(documents, { to: to, config: blacklight_config }, url_options)
275
275
  if mail.respond_to? :deliver_now
276
276
  mail.deliver_now
277
277
  else
@@ -13,7 +13,9 @@ Blacklight = function() {
13
13
 
14
14
  listeners: function () {
15
15
  var listeners = [];
16
- if (typeof Turbolinks !== 'undefined' && Turbolinks.supported) {
16
+ if (typeof Turbo !== 'undefined') {
17
+ listeners.push('turbo:load');
18
+ } else if (typeof Turbolinks !== 'undefined' && Turbolinks.supported) {
17
19
  // Turbolinks 5
18
20
  if (Turbolinks.BrowserAdapter) {
19
21
  listeners.push('turbolinks:load');
@@ -41,6 +43,8 @@ Blacklight.listeners().forEach(function(listener) {
41
43
  Blacklight.onLoad(function () {
42
44
  const elem = document.querySelector('.no-js');
43
45
 
46
+ // The "no-js" class may already have been removed because this function is
47
+ // run on every turbo:load event, in that case, it won't find an element.
44
48
  if (!elem) return;
45
49
 
46
50
  elem.classList.remove('no-js')
@@ -120,7 +120,7 @@ Blacklight.modal.onFailure = function(jqXHR, textStatus, errorThrown) {
120
120
  Blacklight.modal.receiveAjax = function (contents) {
121
121
  // does it have a data- selector for container?
122
122
  // important we don't execute script tags, we shouldn't.
123
- // code modelled off of JQuery ajax.load. https://github.com/jquery/jquery/blob/master/src/ajax/load.js?source=c#L62
123
+ // code modelled off of JQuery ajax.load. https://github.com/jquery/jquery/blob/main/src/ajax/load.js?source=c#L62
124
124
  var container = $('<div>').
125
125
  append( jQuery.parseHTML(contents) ).find( Blacklight.modal.containerSelector ).first();
126
126
  if (container.length !== 0) {
@@ -2,13 +2,25 @@
2
2
  # This module provides the body of an email export based on the document's semantic values
3
3
  module Blacklight::Document::Email
4
4
  # Return a text string that will be the body of the email
5
- def to_email_text
6
- semantics = to_semantic_values
5
+ def to_email_text(config = nil)
7
6
  body = []
8
- body << I18n.t('blacklight.email.text.title', value: semantics[:title].join(" ")) if semantics[:title].present?
9
- body << I18n.t('blacklight.email.text.author', value: semantics[:author].join(" ")) if semantics[:author].present?
10
- body << I18n.t('blacklight.email.text.format', value: semantics[:format].join(" ")) if semantics[:format].present?
11
- body << I18n.t('blacklight.email.text.language', value: semantics[:language].join(" ")) if semantics[:language].present?
7
+
8
+ if config
9
+ body = config.email_fields.map do |name, field|
10
+ values = [self[name]].flatten
11
+ "#{field.label} #{values.join(' ')}" if self[name].present?
12
+ end
13
+ end
14
+
15
+ # Use to_semantic_values for backwards compatibility
16
+ if body.empty?
17
+ semantics = to_semantic_values
18
+ body << I18n.t('blacklight.email.text.title', value: semantics[:title].join(" ")) if semantics[:title].present?
19
+ body << I18n.t('blacklight.email.text.author', value: semantics[:author].join(" ")) if semantics[:author].present?
20
+ body << I18n.t('blacklight.email.text.format', value: semantics[:format].join(" ")) if semantics[:format].present?
21
+ body << I18n.t('blacklight.email.text.language', value: semantics[:language].join(" ")) if semantics[:language].present?
22
+ end
23
+
12
24
  return body.join("\n") unless body.empty?
13
25
  end
14
26
  end
@@ -2,11 +2,23 @@
2
2
  # This module provides the body of an email export based on the document's semantic values
3
3
  module Blacklight::Document::Sms
4
4
  # Return a text string that will be the body of the email
5
- def to_sms_text
6
- semantics = to_semantic_values
5
+ def to_sms_text(config = nil)
7
6
  body = []
8
- body << I18n.t('blacklight.sms.text.title', value: semantics[:title].first) if semantics[:title].present?
9
- body << I18n.t('blacklight.sms.text.author', value: semantics[:author].first) if semantics[:author].present?
7
+
8
+ if config
9
+ body = config.sms_fields.map do |name, field|
10
+ values = [self[name]].flatten
11
+ "#{field.label} #{values.first}" if self[name].present?
12
+ end
13
+ end
14
+
15
+ # Use to_semantic_values for backwards compatibility
16
+ if body.empty?
17
+ semantics = to_semantic_values
18
+ body << I18n.t('blacklight.sms.text.title', value: semantics[:title].first) if semantics[:title].present?
19
+ body << I18n.t('blacklight.sms.text.author', value: semantics[:author].first) if semantics[:author].present?
20
+ end
21
+
10
22
  return body.join unless body.empty?
11
23
  end
12
24
  end
@@ -3,7 +3,12 @@
3
3
  class RecordMailer < ActionMailer::Base
4
4
  def email_record(documents, details, url_gen_params)
5
5
  title = begin
6
- documents.first.to_semantic_values[:title]
6
+ title_field = details[:config].email.title_field
7
+ if title_field
8
+ [documents.first[title_field]].flatten.first
9
+ else
10
+ documents.first.to_semantic_values[:title]
11
+ end
7
12
  rescue
8
13
  I18n.t('blacklight.email.text.default_title')
9
14
  end
@@ -14,6 +19,7 @@ class RecordMailer < ActionMailer::Base
14
19
 
15
20
  @documents = documents
16
21
  @message = details[:message]
22
+ @config = details[:config]
17
23
  @url_gen_params = url_gen_params
18
24
 
19
25
  mail(to: details[:to], subject: subject)
@@ -21,7 +27,9 @@ class RecordMailer < ActionMailer::Base
21
27
 
22
28
  def sms_record(documents, details, url_gen_params)
23
29
  @documents = documents
30
+ @config = details[:config]
24
31
  @url_gen_params = url_gen_params
32
+
25
33
  mail(to: details[:to], subject: "")
26
34
  end
27
35
  end
@@ -56,6 +56,8 @@ module Blacklight
56
56
  view_context.public_send(facet_config.helper_method, label_value)
57
57
  elsif facet_config.query && facet_config.query[label_value]
58
58
  facet_config.query[label_value][:label]
59
+ elsif value == Blacklight::SearchState::FilterField::MISSING
60
+ I18n.t("blacklight.search.facets.missing")
59
61
  elsif facet_config.date
60
62
  localization_options = facet_config.date == true ? {} : facet_config.date
61
63
  I18n.l(Time.zone.parse(label_value), **localization_options)
@@ -1,4 +1,4 @@
1
1
  <% @documents.each do |document| %>
2
- <%= document.to_sms_text %>
2
+ <%= document.to_sms_text(@config) %>
3
3
  <%= t('blacklight.sms.text.url', :url => polymorphic_url(document, @url_gen_params) ) %>
4
4
  <% end %>
@@ -232,7 +232,7 @@ de:
232
232
  entry_name:
233
233
  default:
234
234
  one: Eintrag
235
- other: Enträge
235
+ other: Einträge
236
236
  grouped:
237
237
  default: 'gruppiertes Ergebnis'
238
238
 
@@ -101,6 +101,9 @@ module Blacklight
101
101
  show: { top_level_config: :show },
102
102
  citation: { parent_config: :show }
103
103
  ),
104
+ # SMS and Email configurations.
105
+ sms: ViewConfig.new,
106
+ email: ViewConfig.new,
104
107
  # Configurations for specific types of index views
105
108
  view: NestedOpenStructWithHashAccess.new(ViewConfig,
106
109
  list: {},
@@ -167,6 +170,12 @@ module Blacklight
167
170
  # solr fields to use for sorting results
168
171
  define_field_access :sort_field
169
172
 
173
+ # solr fields to use in text message
174
+ define_field_access :sms_field
175
+
176
+ # solr fields to use in email message
177
+ define_field_access :email_field
178
+
170
179
  def initialize(hash = {})
171
180
  super(self.class.default_values.deep_dup.merge(hash))
172
181
  yield(self) if block_given?
@@ -48,5 +48,7 @@ module Blacklight
48
48
  config.action_dispatch.rescue_responses["Blacklight::Exceptions::RecordNotFound"] = :not_found
49
49
 
50
50
  config.enable_search_bar_autofocus = false
51
+
52
+ config.facet_missing_param = '[* TO *]'
51
53
  end
52
54
  end
@@ -4,6 +4,8 @@ module Blacklight
4
4
  class SearchState
5
5
  # Modeling access to filter query parameters
6
6
  class FilterField
7
+ MISSING = { missing: true }.freeze
8
+
7
9
  # @param [Blacklight::Configuration::FacetField] config
8
10
  attr_reader :config
9
11
 
@@ -25,7 +27,9 @@ module Blacklight
25
27
  def add(item)
26
28
  new_state = search_state.reset_search
27
29
 
28
- if item.respond_to?(:fq)
30
+ if item.try(:missing)
31
+ # if this is a 'missing' facet value, the :fq is only for backwards compatibility
32
+ elsif item.respond_to?(:fq)
29
33
  Array(item.fq).each do |f, v|
30
34
  new_state = new_state.filter(f).add(v)
31
35
  end
@@ -35,21 +39,28 @@ module Blacklight
35
39
  return new_state.filter(item.field).add(item)
36
40
  end
37
41
 
42
+ url_key = key
38
43
  params = new_state.params
39
44
  param = :f
40
45
  value = as_url_parameter(item)
46
+
47
+ if value == Blacklight::SearchState::FilterField::MISSING
48
+ url_key = "-#{key}"
49
+ value = Blacklight::Engine.config.facet_missing_param
50
+ end
51
+
41
52
  param = :f_inclusive if value.is_a?(Array)
42
53
 
43
54
  # value could be a string
44
55
  params[param] = (params[param] || {}).dup
45
56
 
46
57
  if value.is_a? Array
47
- params[param][key] = value
58
+ params[param][url_key] = value
48
59
  elsif config.single
49
- params[param][key] = [value]
60
+ params[param][url_key] = [value]
50
61
  else
51
- params[param][key] = Array(params[param][key] || []).dup
52
- params[param][key].push(value)
62
+ params[param][url_key] = Array(params[param][url_key] || []).dup
63
+ params[param][url_key].push(value)
53
64
  end
54
65
 
55
66
  new_state.reset(params)
@@ -63,19 +74,26 @@ module Blacklight
63
74
  return new_state.filter(item.field).remove(item)
64
75
  end
65
76
 
77
+ url_key = config.key
66
78
  params = new_state.params
67
79
 
68
80
  param = :f
69
81
  value = as_url_parameter(item)
82
+
83
+ if value == Blacklight::SearchState::FilterField::MISSING
84
+ url_key = "-#{key}"
85
+ value = Blacklight::Engine.config.facet_missing_param
86
+ end
87
+
70
88
  param = :f_inclusive if value.is_a?(Array)
71
89
 
72
90
  # need to dup the facet values too,
73
91
  # if the values aren't dup'd, then the values
74
92
  # from the session will get remove in the show view...
75
93
  params[param] = (params[param] || {}).dup
76
- params[param][key] = (params[param][key] || []).dup
94
+ params[param][url_key] = (params[param][url_key] || []).dup
77
95
 
78
- collection = params[param][key]
96
+ collection = params[param][url_key]
79
97
  # collection should be an array, because we link to ?f[key][]=value,
80
98
  # however, Facebook (and maybe some other PHP tools) tranform that parameters
81
99
  # into ?f[key][0]=value, which Rails interprets as a Hash.
@@ -84,18 +102,10 @@ module Blacklight
84
102
  collection = collection.values
85
103
  end
86
104
 
87
- params[param][key] = collection - Array(value)
88
- params[param].delete(key) if params[param][key].empty?
105
+ params[param][url_key] = collection - Array(value)
106
+ params[param].delete(url_key) if params[param][url_key].empty?
89
107
  params.delete(param) if params[param].empty?
90
108
 
91
- # Handle missing field queries.
92
- missing = I18n.t("blacklight.search.facets.missing")
93
- if (item.respond_to?(:fq) && item.fq == "-#{key}:[* TO *]") ||
94
- item == missing
95
- params[param].delete("-#{key}:")
96
- params[param].delete(key) if params[param][key] == [""]
97
- end
98
-
99
109
  new_state.reset(params)
100
110
  end
101
111
 
@@ -104,8 +114,9 @@ module Blacklight
104
114
  params = search_state.params
105
115
  f = Array(params.dig(:f, key))
106
116
  f_inclusive = [params.dig(:f_inclusive, key)] if params.dig(:f_inclusive, key).present?
117
+ f_missing = [Blacklight::SearchState::FilterField::MISSING] if params.dig(:f, "-#{key}")&.any? { |v| v == Blacklight::Engine.config.facet_missing_param }
107
118
 
108
- f + (f_inclusive || [])
119
+ f + (f_inclusive || []) + (f_missing || [])
109
120
  end
110
121
  delegate :any?, to: :values
111
122
 
@@ -121,6 +132,8 @@ module Blacklight
121
132
 
122
133
  if value.is_a?(Array)
123
134
  (params.dig(:f_inclusive, key) || []).to_set == value.to_set
135
+ elsif value == Blacklight::SearchState::FilterField::MISSING
136
+ (params.dig(:f, "-#{key}") || []).include?(Blacklight::Engine.config.facet_missing_param)
124
137
  else
125
138
  (params.dig(:f, key) || []).include?(value)
126
139
  end
@@ -130,7 +143,9 @@ module Blacklight
130
143
 
131
144
  # TODO: this code is duplicated in Blacklight::FacetsHelperBehavior
132
145
  def as_url_parameter(item)
133
- if item.respond_to? :value
146
+ if item.respond_to?(:missing) && item.missing
147
+ Blacklight::SearchState::FilterField::MISSING
148
+ elsif item.respond_to? :value
134
149
  item.value
135
150
  else
136
151
  item
@@ -171,7 +171,8 @@ module Blacklight::Solr::Response::Facets
171
171
  # legacy solr facet.missing serialization
172
172
  if value.nil?
173
173
  i.label = I18n.t(:"blacklight.search.fields.facet.missing.#{facet_field_name}", default: [:"blacklight.search.facets.missing"])
174
- i.fq = "-#{facet_field_name}:[* TO *]"
174
+ i.fq = "-#{facet_field_name}:[* TO *]" # this explicit fq is deprecated; the missing attribute below is a better thing to check for this case
175
+ i.value = Blacklight::SearchState::FilterField::MISSING
175
176
  i.missing = true
176
177
  end
177
178
 
@@ -10,7 +10,6 @@ module Blacklight::Solr
10
10
  :add_facetting_to_solr, :add_solr_fields_to_query, :add_paging_to_solr,
11
11
  :add_sorting_to_solr, :add_group_config_to_solr,
12
12
  :add_facet_paging_to_solr, :add_adv_search_clauses,
13
- :add_missing_field_query,
14
13
  :add_additional_filters
15
14
  ]
16
15
  end
@@ -82,19 +81,6 @@ module Blacklight::Solr
82
81
  end
83
82
  end
84
83
 
85
- ##
86
- # Build and append a missing field query.
87
- ##
88
- def add_missing_field_query(solr_parameters)
89
- return unless solr_parameters["facet.missing"]
90
-
91
- solr_parameters[:fq] = [] if solr_parameters[:fq].blank?
92
-
93
- solr_parameters[:fq].append(*(blacklight_params["f"] || [])
94
- .select { |f| f.match(/^-/) }
95
- .map { |k, _v| "#{k}[* TO *]" })
96
- end
97
-
98
84
  def add_additional_filters(solr_parameters, additional_filters = nil)
99
85
  q = additional_filters || @additional_filters
100
86
 
@@ -384,6 +370,8 @@ module Blacklight::Solr
384
370
  elsif value.is_a?(Range)
385
371
  prefix = "{!#{local_params.join(' ')}}" unless local_params.empty?
386
372
  "#{prefix}#{solr_field}:[#{value.first} TO #{value.last}]"
373
+ elsif value == Blacklight::SearchState::FilterField::MISSING
374
+ "-#{solr_field}:[* TO *]"
387
375
  else
388
376
  "{!term f=#{solr_field}#{(' ' + local_params.join(' ')) unless local_params.empty?}}#{convert_to_term_value(value)}"
389
377
  end
data/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "blacklight-frontend",
3
3
  "version": "7.20.1",
4
- "description": "[![Build Status](https://travis-ci.com/projectblacklight/blacklight.png?branch=master)](https://travis-ci.com/projectblacklight/blacklight) [![Gem Version](https://badge.fury.io/rb/blacklight.png)](http://badge.fury.io/rb/blacklight) [![Coverage Status](https://coveralls.io/repos/github/projectblacklight/blacklight/badge.svg?branch=master)](https://coveralls.io/github/projectblacklight/blacklight?branch=master)",
4
+ "description": "[![Build Status](https://travis-ci.com/projectblacklight/blacklight.png?branch=main)](https://travis-ci.com/projectblacklight/blacklight) [![Gem Version](https://badge.fury.io/rb/blacklight.png)](http://badge.fury.io/rb/blacklight) [![Coverage Status](https://coveralls.io/repos/github/projectblacklight/blacklight/badge.svg?branch=main)](https://coveralls.io/github/projectblacklight/blacklight?branch=main)",
5
5
  "main": "app/assets/javascripts/blacklight",
6
6
  "scripts": {
7
7
  "js-compile-bundle": "shx cat app/javascript/blacklight/core.js app/javascript/blacklight/autocomplete.js app/javascript/blacklight/bookmark_toggle.js app/javascript/blacklight/button_focus.js app/javascript/blacklight/checkbox_submit.js app/javascript/blacklight/facet_load.js app/javascript/blacklight/modal.js app/javascript/blacklight/search_context.js | shx sed \"s/^(import|export).*//\" | babel --filename app/javascript/blacklight/blacklight.js > app/assets/javascripts/blacklight/blacklight.js"
@@ -23,8 +23,10 @@
23
23
  "devDependencies": {
24
24
  "@babel/cli": "^7.2.3",
25
25
  "@babel/core": "^7.2.3",
26
+ "@babel/preset-env": "^7.16.0",
26
27
  "shx": "^0.3.2"
27
28
  },
29
+ "browserslist": "> 0.25%, not dead",
28
30
  "dependencies": {
29
31
  "bloodhound-js": "^1.2.3",
30
32
  "bootstrap": ">=4.3.1 <6.0.0",
@@ -501,6 +501,12 @@ RSpec.describe CatalogController, api: true do
501
501
  end
502
502
 
503
503
  describe "email", api: false do
504
+ let(:config) { Blacklight::Configuration.new }
505
+
506
+ before do
507
+ allow(controller).to receive(:blacklight_config).and_return(config)
508
+ end
509
+
504
510
  it "gives error if no TO parameter" do
505
511
  post :email, params: { id: doc_id }
506
512
  expect(request.flash[:error]).to eq "You must enter a recipient in order to send this message"
@@ -518,7 +524,7 @@ RSpec.describe CatalogController, api: true do
518
524
 
519
525
  it "redirects back to the record upon success" do
520
526
  allow(RecordMailer).to receive(:email_record)
521
- .with(anything, { to: 'test_email@projectblacklight.org', message: 'xyz' }, hash_including(host: 'test.host'))
527
+ .with(anything, { to: 'test_email@projectblacklight.org', message: 'xyz', config: config }, hash_including(host: 'test.host'))
522
528
  .and_return double(deliver: nil)
523
529
  post :email, params: { id: doc_id, to: 'test_email@projectblacklight.org', message: 'xyz' }
524
530
  expect(request.flash[:error]).to be_nil
@@ -533,6 +539,12 @@ RSpec.describe CatalogController, api: true do
533
539
  end
534
540
 
535
541
  describe "sms", api: false do
542
+ let(:config) { Blacklight::Configuration.new }
543
+
544
+ before do
545
+ allow(controller).to receive(:blacklight_config).and_return(config)
546
+ end
547
+
536
548
  it "gives error if no phone number is given" do
537
549
  post :sms, params: { id: doc_id, carrier: 'att' }
538
550
  expect(request.flash[:error]).to eq "You must enter a recipient's phone number in order to send this message"
@@ -562,7 +574,7 @@ RSpec.describe CatalogController, api: true do
562
574
  it "sends to the appropriate carrier email address" do
563
575
  expect(RecordMailer)
564
576
  .to receive(:sms_record)
565
- .with(anything, { to: '5555555555@txt.att.net' }, hash_including(host: 'test.host'))
577
+ .with(anything, { to: '5555555555@txt.att.net', config: config }, hash_including(host: 'test.host'))
566
578
  .and_return double(deliver: nil)
567
579
  post :sms, params: { id: doc_id, to: '5555555555', carrier: 'txt.att.net' }
568
580
  end
@@ -1,34 +1,33 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  RSpec.describe 'Accessibility testing', api: false, js: true do
4
- xit 'validates the home page' do
4
+ it 'validates the home page' do
5
5
  visit root_path
6
6
  expect(page).to be_accessible
7
7
  end
8
8
 
9
- xit 'validates the catalog page' do
9
+ it 'validates the catalog page' do
10
10
  visit root_path
11
11
  fill_in "q", with: 'history'
12
12
  click_button 'search'
13
13
 
14
- # aria-allowed-role doesn't like nav[role="region"]
15
- expect(page).to be_accessible(skipping: ['aria-allowed-role'])
14
+ expect(page).to be_accessible
16
15
 
17
16
  within '.card.blacklight-language_ssim' do
18
17
  click_button 'Language'
19
18
  click_link "Tibetan"
20
19
  end
21
20
 
22
- expect(page).to be_accessible(skipping: ['aria-allowed-role'])
21
+ expect(page).to be_accessible
23
22
  end
24
23
 
25
- xit 'validates the single results page' do
24
+ it 'validates the single results page' do
26
25
  visit solr_document_path('2007020969')
27
26
  expect(page).to be_accessible
28
27
  end
29
28
 
30
29
  def be_accessible(skipping: [])
31
30
  # typeahead does funny things with the search bar
32
- be_axe_clean.excluding('.tt-hint').skipping(skipping + [('color-contrast' if Bootstrap::VERSION < '5')])
31
+ be_axe_clean.excluding('.tt-hint').skipping(skipping + [('color-contrast' if Bootstrap::VERSION < '5')].compact)
33
32
  end
34
33
  end
@@ -32,8 +32,12 @@ RSpec.describe "Facet missing" do
32
32
  end
33
33
 
34
34
  context "unselecting the facet missing facet" do
35
- it "unselects the missig field facet" do
36
- visit root_path + "?f[-subject_geo_ssim:[* TO *]][]=&f[subject_geo_ssim][]="
35
+ it "unselects the missing field facet" do
36
+ visit root_path
37
+
38
+ within "#facet-subject_geo_ssim" do
39
+ click_link "[Missing]"
40
+ end
37
41
 
38
42
  within "#facet-subject_geo_ssim" do
39
43
  click_link "remove"
@@ -45,8 +49,12 @@ RSpec.describe "Facet missing" do
45
49
  end
46
50
 
47
51
  context "unselecting the facet missing constraint" do
48
- it "unselects the missig field facet" do
49
- visit root_path + "?f[-subject_geo_ssim:[* TO *]][]=&f[subject_geo_ssim][]="
52
+ it "unselects the missing field facet" do
53
+ visit root_path
54
+
55
+ within "#facet-subject_geo_ssim" do
56
+ click_link "[Missing]"
57
+ end
50
58
 
51
59
  within ".filter-subject_geo_ssim" do
52
60
  click_link "Remove constraint Region: [Missing]"
@@ -162,28 +162,14 @@ RSpec.describe Blacklight::SearchState::FilterField do
162
162
 
163
163
  context "With facet.missing field" do
164
164
  let(:params) do
165
- { f: { some_field: [""], "-some_field:": [""] } }
165
+ { f: { "-some_field": ["[* TO *]"] } }
166
166
  end
167
167
 
168
168
  it "removes facet.missing facet params" do
169
169
  filter = search_state.filter("some_field")
170
- new_state = filter.remove(OpenStruct.new(fq: "-some_field:[* TO *]"))
170
+ new_state = filter.remove(OpenStruct.new(key: 'some_field', missing: true))
171
171
 
172
- expect(new_state.params).to eq("f" => {})
173
- end
174
- end
175
-
176
- context "With facet.missing field value" do
177
- let(:params) do
178
- { f: { some_field: [""], "-some_field:": [""] } }
179
- end
180
-
181
- it "removes facet.missing facet params" do
182
- missing = I18n.t("blacklight.search.facets.missing")
183
- filter = search_state.filter("some_field")
184
- new_state = filter.remove(missing)
185
-
186
- expect(new_state.params).to eq("f" => {})
172
+ expect(new_state.params).to eq({})
187
173
  end
188
174
  end
189
175
  end
@@ -543,6 +543,98 @@ RSpec.describe "Blacklight::Configuration", api: true do
543
543
  end
544
544
  end
545
545
 
546
+ describe "add_sms_field" do
547
+ it "takes hash form" do
548
+ config.add_sms_field("title_tsim", label: "Title")
549
+
550
+ expect(config.sms_fields["title_tsim"]).not_to be_nil
551
+ expect(config.sms_fields["title_tsim"].label).to eq "Title"
552
+ end
553
+
554
+ it "takes ShowField argument" do
555
+ config.add_sms_field("title_tsim", Blacklight::Configuration::SmsField.new(field: "title_display", label: "Title"))
556
+
557
+ expect(config.sms_fields["title_tsim"]).not_to be_nil
558
+ expect(config.sms_fields["title_tsim"].label).to eq "Title"
559
+ end
560
+
561
+ it "takes block form" do
562
+ config.add_sms_field("title_tsim") do |f|
563
+ f.label = "Title"
564
+ end
565
+
566
+ expect(config.sms_fields["title_tsim"]).not_to be_nil
567
+ expect(config.sms_fields["title_tsim"].label).to eq "Title"
568
+ end
569
+
570
+ it "creates default label humanized from field" do
571
+ config.add_sms_field("my_custom_field")
572
+
573
+ expect(config.sms_fields["my_custom_field"].label).to eq "My Custom Field"
574
+ end
575
+
576
+ it "raises on nil solr field name" do
577
+ expect { config.add_sms_field(nil) }.to raise_error ArgumentError
578
+ end
579
+
580
+ it "takes wild-carded field names and dereference them to solr fields" do
581
+ allow(config).to receive(:reflected_fields).and_return(
582
+ "some_field_display" => {},
583
+ "another_field_display" => {},
584
+ "a_facet_field" => {}
585
+ )
586
+ config.add_sms_field "*_display"
587
+
588
+ expect(config.sms_fields.keys).to eq %w[some_field_display another_field_display]
589
+ end
590
+ end
591
+
592
+ describe "add_email_field" do
593
+ it "takes hash form" do
594
+ config.add_email_field("title_tsim", label: "Title")
595
+
596
+ expect(config.email_fields["title_tsim"]).not_to be_nil
597
+ expect(config.email_fields["title_tsim"].label).to eq "Title"
598
+ end
599
+
600
+ it "takes ShowField argument" do
601
+ config.add_email_field("title_tsim", Blacklight::Configuration::EmailField.new(field: "title_display", label: "Title"))
602
+
603
+ expect(config.email_fields["title_tsim"]).not_to be_nil
604
+ expect(config.email_fields["title_tsim"].label).to eq "Title"
605
+ end
606
+
607
+ it "takes block form" do
608
+ config.add_email_field("title_tsim") do |f|
609
+ f.label = "Title"
610
+ end
611
+
612
+ expect(config.email_fields["title_tsim"]).not_to be_nil
613
+ expect(config.email_fields["title_tsim"].label).to eq "Title"
614
+ end
615
+
616
+ it "creates default label humanized from field" do
617
+ config.add_email_field("my_custom_field")
618
+
619
+ expect(config.email_fields["my_custom_field"].label).to eq "My Custom Field"
620
+ end
621
+
622
+ it "raises on nil solr field name" do
623
+ expect { config.add_email_field(nil) }.to raise_error ArgumentError
624
+ end
625
+
626
+ it "takes wild-carded field names and dereference them to solr fields" do
627
+ allow(config).to receive(:reflected_fields).and_return(
628
+ "some_field_display" => {},
629
+ "another_field_display" => {},
630
+ "a_facet_field" => {}
631
+ )
632
+ config.add_email_field "*_display"
633
+
634
+ expect(config.email_fields.keys).to eq %w[some_field_display another_field_display]
635
+ end
636
+ end
637
+
546
638
  describe "#default_search_field" do
547
639
  it "uses the field with a :default key" do
548
640
  config.add_search_field('search_field_1')
@@ -1,6 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  RSpec.describe "Blacklight::Document::Email" do
4
+ let(:config) do
5
+ Blacklight::Configuration.new
6
+ end
7
+
4
8
  before(:all) do
5
9
  SolrDocument.use_extension(Blacklight::Document::Email)
6
10
  end
@@ -22,4 +26,32 @@ RSpec.describe "Blacklight::Document::Email" do
22
26
  doc = SolrDocument.new(id: "1234")
23
27
  expect(doc.to_email_text).to be_nil
24
28
  end
29
+
30
+ context "we pass in configuration with email fields set" do
31
+ it "uses the email fields for to_email_text" do
32
+ config.add_email_field("foo", label: "Foo:")
33
+ config.add_email_field("bar", label: "Bar:")
34
+ doc = SolrDocument.new(id: "1234", foo: ["Fuzz Fuzz", "Fizz Fizz"], bar: ["Buzz Buzz", "Bizz Bizz"])
35
+
36
+ expect(doc.to_email_text(config)).to eq("Foo: Fuzz Fuzz Fizz Fizz\nBar: Buzz Buzz Bizz Bizz")
37
+ end
38
+ end
39
+
40
+ context "we pass in configuration with email fields no set" do
41
+ it "falls back on default semantics setup" do
42
+ doc = SolrDocument.new(id: "1234", title_tsim: ["My Title", "My Alt. Title"])
43
+ email_body = doc.to_email_text(config)
44
+ expect(email_body).to match(/Title: My Title/)
45
+ end
46
+ end
47
+
48
+ context "document field is single valued" do
49
+ it "handles the single value field correctly" do
50
+ config.add_email_field("foo", label: "Foo:")
51
+ config.add_email_field("bar", label: "Bar:")
52
+ doc = SolrDocument.new(id: "1234", foo: "Fuzz Fuzz", bar: ["Buzz Buzz", "Bizz Bizz"])
53
+
54
+ expect(doc.to_email_text(config)).to eq("Foo: Fuzz Fuzz\nBar: Buzz Buzz Bizz Bizz")
55
+ end
56
+ end
25
57
  end
@@ -1,6 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  RSpec.describe "Blacklight::Document::Email" do
4
+ let(:config) do
5
+ Blacklight::Configuration.new
6
+ end
7
+
4
8
  before(:all) do
5
9
  SolrDocument.use_extension(Blacklight::Document::Sms)
6
10
  end
@@ -22,4 +26,33 @@ RSpec.describe "Blacklight::Document::Email" do
22
26
  doc = SolrDocument.new(id: "1234")
23
27
  expect(doc.to_sms_text).to be_nil
24
28
  end
29
+
30
+ context "we pass in configuration with sms fields set" do
31
+ it "uses the sms fields for to_sms_text" do
32
+ config.add_sms_field("foo", label: "Foo:")
33
+ config.add_sms_field("bar", label: " by")
34
+ doc = SolrDocument.new(id: "1234", foo: ["Fuzz Fuzz", "Fizz Fizz"], bar: ["Buzz Buzz", "Bizz Bizz"])
35
+
36
+ expect(doc.to_sms_text(config)).to eq("Foo: Fuzz Fuzz by Buzz Buzz")
37
+ end
38
+ end
39
+
40
+ context "we pass in configuration with sms fields no set" do
41
+ it "falls back on default semantics setup" do
42
+ doc = SolrDocument.new(id: "1234", title_tsim: ["My Title", "My Alt. Title"])
43
+ sms_text = doc.to_sms_text(config)
44
+ expect(sms_text).to match(/My Title/)
45
+ expect(sms_text).not_to match(/My Alt\. Title/)
46
+ end
47
+ end
48
+
49
+ context "document field is single valued" do
50
+ it "handles the single value field correctly" do
51
+ config.add_sms_field("foo", label: "Foo:")
52
+ config.add_sms_field("bar", label: " by")
53
+ doc = SolrDocument.new(id: "1234", foo: "Fuzz Fuzz", bar: ["Buzz Buzz", "Bizz Bizz"])
54
+
55
+ expect(doc.to_sms_text(config)).to eq("Foo: Fuzz Fuzz by Buzz Buzz")
56
+ end
57
+ end
25
58
  end
@@ -155,7 +155,7 @@ RSpec.describe Blacklight::Solr::Response::Facets, api: true do
155
155
  end
156
156
 
157
157
  it "marks the facet.missing field with a human-readable label and fq" do
158
- missing = subject.aggregations["some_field"].items.find { |i| i.value.nil? }
158
+ missing = subject.aggregations["some_field"].items.find(&:missing)
159
159
 
160
160
  expect(missing.label).to eq "[Missing]"
161
161
  expect(missing.fq).to eq "-some_field:[* TO *]"
@@ -27,10 +27,6 @@ RSpec.describe Blacklight::Solr::SearchBuilderBehavior, api: true do
27
27
  it "uses the class-level default_processor_chain" do
28
28
  expect(subject.processor_chain).to eq search_builder_class.default_processor_chain
29
29
  end
30
-
31
- it "appends the :add_missing_field_query processor" do
32
- expect(subject.processor_chain).to include(:add_missing_field_query)
33
- end
34
30
  end
35
31
 
36
32
  context 'with merged parameters from the defaults + the search field' do
@@ -826,13 +822,4 @@ RSpec.describe Blacklight::Solr::SearchBuilderBehavior, api: true do
826
822
  expect(subject.to_hash).to include q: '{!lucene}id:(1 OR 2 OR 3)'
827
823
  end
828
824
  end
829
-
830
- describe "#add_missing_field_query" do
831
- it "precesses facet.missing query" do
832
- subject.with("f" => { "-hello:" => [""] })
833
- solr_params = { "facet.missing" => true, fq: [] }
834
-
835
- expect(subject.add_missing_field_query(solr_params)).to eq(["-hello:[* TO *]"])
836
- end
837
- end
838
825
  end
@@ -1,17 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  RSpec.describe RecordMailer do
4
+ let(:config) do
5
+ Blacklight::Configuration.new
6
+ end
7
+
8
+ let(:document) do
9
+ SolrDocument.new(id: "123456", format: ["book"], title_tsim: "The horn", language_ssim: "English", author_tsim: "Janetzky, Kurt")
10
+ end
11
+
4
12
  before do
5
13
  allow(described_class).to receive(:default).and_return(from: 'no-reply@projectblacklight.org')
6
14
  SolrDocument.use_extension(Blacklight::Document::Email)
7
15
  SolrDocument.use_extension(Blacklight::Document::Sms)
8
- document = SolrDocument.new(id: "123456", format: ["book"], title_tsim: "The horn", language_ssim: "English", author_tsim: "Janetzky, Kurt")
9
16
  @documents = [document]
10
17
  end
11
18
 
12
19
  describe "email" do
13
20
  before do
14
- details = { to: 'test@test.com', message: "This is my message" }
21
+ details = { to: 'test@test.com', message: "This is my message", config: config }
15
22
  @email = described_class.email_record(@documents, details, host: 'projectblacklight.org', protocol: 'https')
16
23
  end
17
24
 
@@ -42,6 +49,27 @@ RSpec.describe RecordMailer do
42
49
  @https_email = described_class.email_record(@documents, details, host: 'projectblacklight.org', protocol: 'https')
43
50
  expect(@https_email.body).to match %r{https://projectblacklight.org/}
44
51
  end
52
+
53
+ context "email title_field is configured and multi valued" do
54
+ let(:document) { SolrDocument.new(id: "123456", foo: ["Fizz Fizz", "Fuzz Fuzz"], format: ["book"], title_tsim: "The horn", language_ssim: "English", author_tsim: "Janetzky, Kurt") }
55
+
56
+ it "uses configured email title_field" do
57
+ config.email.title_field = "foo"
58
+ expect(@email.subject).to match("Fizz Fizz")
59
+ expect(@email.subject).not_to match("Fuzz Fuzz")
60
+ expect(@email.subject).not_to match("The horn")
61
+ end
62
+ end
63
+
64
+ context "email title_field is configured and single valued" do
65
+ let(:document) { SolrDocument.new(id: "123456", foo: "Fizz Fizz", format: ["book"], title_tsim: "The horn", language_ssim: "English", author_tsim: "Janetzky, Kurt") }
66
+
67
+ it "uses configured email title_field" do
68
+ config.email.title_field = "foo"
69
+ expect(@email.subject).to match("Fizz Fizz")
70
+ expect(@email.subject).not_to match("The horn")
71
+ end
72
+ end
45
73
  end
46
74
 
47
75
  describe "SMS" do
data/spec/spec_helper.rb CHANGED
@@ -10,9 +10,6 @@ SimpleCov.start do
10
10
  add_filter "/spec/"
11
11
  end
12
12
 
13
- require 'rsolr'
14
- require 'blacklight'
15
-
16
13
  require 'engine_cart'
17
14
  EngineCart.load_application!
18
15
 
@@ -25,6 +22,9 @@ require 'selenium-webdriver'
25
22
  require 'equivalent-xml'
26
23
  require 'axe-rspec'
27
24
 
25
+ require 'rsolr'
26
+ require 'blacklight'
27
+
28
28
  Capybara.javascript_driver = :headless_chrome
29
29
 
30
30
  Capybara.register_driver :headless_chrome do |app|
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: blacklight
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.20.1
4
+ version: 7.21.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonathan Rochkind
@@ -14,10 +14,10 @@ authors:
14
14
  - Dan Funk
15
15
  - Naomi Dushay
16
16
  - Justin Coyne
17
- autorequire:
17
+ autorequire:
18
18
  bindir: exe
19
19
  cert_chain: []
20
- date: 2021-11-02 00:00:00.000000000 Z
20
+ date: 2021-11-16 00:00:00.000000000 Z
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency
23
23
  name: rails
@@ -378,6 +378,7 @@ executables: []
378
378
  extensions: []
379
379
  extra_rdoc_files: []
380
380
  files:
381
+ - ".babelrc"
381
382
  - ".docker/app/Dockerfile"
382
383
  - ".docker/app/entrypoint.sh"
383
384
  - ".env"
@@ -918,7 +919,7 @@ homepage: http://projectblacklight.org/
918
919
  licenses:
919
920
  - Apache 2.0
920
921
  metadata: {}
921
- post_install_message:
922
+ post_install_message:
922
923
  rdoc_options: []
923
924
  require_paths:
924
925
  - lib
@@ -933,8 +934,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
933
934
  - !ruby/object:Gem::Version
934
935
  version: '0'
935
936
  requirements: []
936
- rubygems_version: 3.1.4
937
- signing_key:
937
+ rubygems_version: 3.2.3
938
+ signing_key:
938
939
  specification_version: 4
939
940
  summary: Blacklight provides a discovery interface for any Solr (http://lucene.apache.org/solr)
940
941
  index.