blacklight 7.20.1 → 7.21.0

Sign up to get free protection for your applications and to get access to all the features.
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.