blacklight 7.20.1 → 7.22.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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/.babelrc +11 -0
  3. data/.docker/app/Dockerfile +3 -1
  4. data/.dockerignore +3 -0
  5. data/.env +2 -2
  6. data/.github/workflows/ruby.yml +3 -2
  7. data/Gemfile +1 -1
  8. data/README.md +1 -1
  9. data/VERSION +1 -1
  10. data/app/assets/javascripts/blacklight/blacklight.js +62 -32
  11. data/app/assets/stylesheets/blacklight/_constraints.scss +3 -1
  12. data/app/assets/stylesheets/blacklight/_controls.scss +2 -1
  13. data/app/components/blacklight/constraints_component.rb +3 -7
  14. data/app/components/blacklight/facet_field_checkboxes_component.rb +1 -1
  15. data/app/components/blacklight/facet_item_pivot_component.rb +1 -1
  16. data/app/components/blacklight/system/modal_component.html.erb +2 -2
  17. data/app/controllers/concerns/blacklight/catalog.rb +2 -2
  18. data/app/helpers/blacklight/facets_helper_behavior.rb +1 -1
  19. data/app/helpers/blacklight/render_partials_helper_behavior.rb +4 -1
  20. data/app/javascript/blacklight/core.js +8 -2
  21. data/app/javascript/blacklight/modal.js +20 -4
  22. data/app/models/concerns/blacklight/document/email.rb +18 -6
  23. data/app/models/concerns/blacklight/document/sms.rb +16 -4
  24. data/app/models/record_mailer.rb +9 -1
  25. data/app/presenters/blacklight/facet_item_presenter.rb +2 -0
  26. data/app/views/bookmarks/index.html.erb +1 -1
  27. data/app/views/catalog/_search_results.html.erb +1 -1
  28. data/app/views/record_mailer/sms_record.text.erb +1 -1
  29. data/config/locales/blacklight.de.yml +1 -1
  30. data/docker-compose.yml +5 -2
  31. data/lib/blacklight/configuration/facet_field.rb +2 -0
  32. data/lib/blacklight/configuration.rb +9 -0
  33. data/lib/blacklight/engine.rb +2 -0
  34. data/lib/blacklight/search_state/filter_field.rb +34 -19
  35. data/lib/blacklight/solr/response/facets.rb +14 -5
  36. data/lib/blacklight/solr/search_builder_behavior.rb +2 -14
  37. data/package.json +4 -2
  38. data/spec/controllers/catalog_controller_spec.rb +14 -2
  39. data/spec/features/axe_spec.rb +6 -7
  40. data/spec/features/facet_missing_spec.rb +12 -4
  41. data/spec/helpers/blacklight/facets_helper_behavior_spec.rb +7 -7
  42. data/spec/lib/blacklight/search_state/filter_field_spec.rb +3 -17
  43. data/spec/models/blacklight/configuration_spec.rb +92 -0
  44. data/spec/models/blacklight/document/email_spec.rb +32 -0
  45. data/spec/models/blacklight/document/sms_spec.rb +33 -0
  46. data/spec/models/blacklight/solr/response/facets_spec.rb +7 -1
  47. data/spec/models/blacklight/solr/search_builder_spec.rb +0 -13
  48. data/spec/models/record_mailer_spec.rb +30 -2
  49. data/spec/spec_helper.rb +3 -3
  50. data/tasks/blacklight.rake +5 -1
  51. metadata +8 -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: 100a7b0ab6394c96ba5ad5606bffe36132721d9f09c5946911845f117d8bddee
4
+ data.tar.gz: a57654c6cdb05add30658903b407d86661a8b975b0af389f84c56736bff2d56c
5
5
  SHA512:
6
- metadata.gz: 97d968403618ee1d25fac527cea64467e3be78040e0d58e8d672463b94c22f272ff7b30fec66af576084bf2a9e8d169a7d3bec9b58b0d1187bb8ffc5bdab2f21
7
- data.tar.gz: 31855c12d2d58eb7863aa90a4b60c106d208b302460bd0f263fdd32baf8d6025f94025cdf953c82a42220a403c2d0eeae367e7729c7f714f8bc19d23bb561974
6
+ metadata.gz: dec089984409283e902abf6d3a79c549a1785742396dd6d1e6dbd8ec5b49b1ec5ae4be46cad25eb5bdff663880fce761e023c313f71a020f989f17932492adb4
7
+ data.tar.gz: d1bb132cc0ef21f5f9c3a715bf407c47eba801f274d7d78f5e872b6f495298d5bad2720ee89e84944c733babcda22ec62f6d8eed119df9e7ded38b70fd5de1b7
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,8 +9,10 @@ RUN apk add --update --no-cache \
9
9
  libxml2-dev \
10
10
  libxslt-dev \
11
11
  nodejs \
12
+ shared-mime-info \
12
13
  sqlite-dev \
13
- tzdata
14
+ tzdata \
15
+ yarn
14
16
 
15
17
  RUN mkdir /app
16
18
  WORKDIR /app
data/.dockerignore ADDED
@@ -0,0 +1,3 @@
1
+ Gemfile.lock
2
+ .internal_test_app
3
+ .solr_wrapper.yml
data/.env CHANGED
@@ -1,5 +1,5 @@
1
- ALPINE_RUBY_VERSION=2.6.5
2
- RAILS_VERSION=5.2.5
1
+ ALPINE_RUBY_VERSION=2.7.5
2
+ RAILS_VERSION=5.2.6
3
3
  SOLR_PORT=8983
4
4
  SOLR_URL=http://solr:8983/solr/blacklight-core
5
5
  SOLR_VERSION=latest
@@ -9,9 +9,10 @@ name: CI
9
9
 
10
10
  on:
11
11
  push:
12
- branches: [ master ]
12
+ branches:
13
+ - main
14
+ - 'release-*'
13
15
  pull_request:
14
- branches: [ master ]
15
16
 
16
17
  jobs:
17
18
  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.22.0
@@ -1,18 +1,22 @@
1
- Blacklight = function () {
1
+ "use strict";
2
+
3
+ var 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,11 +41,14 @@ 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');
44
50
  });
51
+ window.Blacklight = Blacklight;
45
52
  /*global Bloodhound */
46
53
 
47
54
  Blacklight.onLoad(function () {
@@ -87,7 +94,7 @@ Blacklight.onLoad(function () {
87
94
  $(Blacklight.doBookmarkToggleBehavior.selector).blCheckboxSubmit({
88
95
  // cssClass is added to elements added, plus used for id base
89
96
  cssClass: 'toggle-bookmark',
90
- success: function (checked, response) {
97
+ success: function success(checked, response) {
91
98
  if (response.bookmarks) {
92
99
  $('[data-role=bookmark-counter]').text(response.bookmarks.count);
93
100
  }
@@ -105,8 +112,8 @@ Blacklight.onLoad(function () {
105
112
  // Button clicks should change focus. As of 10/3/19, Firefox for Mac and
106
113
  // Safari both do not set focus to a button on button click.
107
114
  // See https://zellwk.com/blog/inconsistent-button-behavior/ for background information
108
- document.querySelectorAll('button.collapse-toggle').forEach(button => {
109
- button.addEventListener('click', () => {
115
+ document.querySelectorAll('button.collapse-toggle').forEach(function (button) {
116
+ button.addEventListener('click', function () {
110
117
  event.target.focus();
111
118
  });
112
119
  });
@@ -193,12 +200,12 @@ Blacklight.onLoad(function () {
193
200
  dataType: 'json',
194
201
  type: form.attr('method').toUpperCase(),
195
202
  data: form.serialize(),
196
- error: function () {
203
+ error: function error() {
197
204
  label.removeAttr('disabled');
198
205
  checkbox.removeAttr('disabled');
199
206
  options.error.call();
200
207
  },
201
- success: function (data, status, xhr) {
208
+ success: function success(data, status, xhr) {
202
209
  //if app isn't running at all, xhr annoyingly
203
210
  //reports success with status 0.
204
211
  if (xhr.status != 0) {
@@ -224,10 +231,10 @@ Blacklight.onLoad(function () {
224
231
  $.fn.blCheckboxSubmit.defaults = {
225
232
  //cssClass is added to elements added, plus used for id base
226
233
  cssClass: 'blCheckboxSubmit',
227
- error: function () {
234
+ error: function error() {
228
235
  alert("Error");
229
236
  },
230
- success: function () {} //callback
237
+ success: function success() {} //callback
231
238
 
232
239
  };
233
240
  })(jQuery);
@@ -243,12 +250,12 @@ Blacklight.doResizeFacetLabelsAndCounts = function () {
243
250
  }
244
251
 
245
252
  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:
253
+ var nodes = elem.querySelectorAll('.facet-count'); // TODO: when we drop ie11 support, this can become the spread operator:
247
254
 
248
- const longest = Array.from(nodes).sort(longer)[0];
255
+ var longest = Array.from(nodes).sort(longer)[0];
249
256
 
250
257
  if (longest && longest.textContent) {
251
- const width = longest.textContent.length + 1 + 'ch';
258
+ var width = longest.textContent.length + 1 + 'ch';
252
259
  elem.querySelector('.facet-count').style.width = width;
253
260
  }
254
261
  });
@@ -359,13 +366,13 @@ Blacklight.modal.onFailure = function (jqXHR, textStatus, errorThrown) {
359
366
  console.error('Server error:', this.url, jqXHR.status, errorThrown);
360
367
  var contents = '<div class="modal-header">' + '<div class="modal-title">There was a problem with your request.</div>' + '<button type="button" class="blacklight-modal-close btn-close close" data-dismiss="modal" aria-label="Close">' + ' <span aria-hidden="true">&times;</span>' + '</button></div>' + ' <div class="modal-body"><p>Expected a successful response from the server, but got an error</p>' + '<pre>' + this.type + ' ' + this.url + "\n" + jqXHR.status + ': ' + errorThrown + '</pre></div>';
361
368
  $(Blacklight.modal.modalSelector).find('.modal-content').html(contents);
362
- $(Blacklight.modal.modalSelector).modal('show');
369
+ Blacklight.modal.show();
363
370
  };
364
371
 
365
372
  Blacklight.modal.receiveAjax = function (contents) {
366
373
  // does it have a data- selector for container?
367
374
  // 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
375
+ // code modelled off of JQuery ajax.load. https://github.com/jquery/jquery/blob/main/src/ajax/load.js?source=c#L62
369
376
  var container = $('<div>').append(jQuery.parseHTML(contents)).find(Blacklight.modal.containerSelector).first();
370
377
 
371
378
  if (container.length !== 0) {
@@ -378,7 +385,7 @@ Blacklight.modal.receiveAjax = function (contents) {
378
385
  $(Blacklight.modal.modalSelector).trigger(e); // if they did preventDefault, don't show the dialog
379
386
 
380
387
  if (e.isDefaultPrevented()) return;
381
- $(Blacklight.modal.modalSelector).modal('show');
388
+ Blacklight.modal.show();
382
389
  };
383
390
 
384
391
  Blacklight.modal.modalAjaxLinkClick = function (e) {
@@ -425,7 +432,7 @@ Blacklight.modal.setupModal = function () {
425
432
  Blacklight.modal.checkCloseModal = function (event) {
426
433
  if ($(event.target).find(Blacklight.modal.modalCloseSelector).length) {
427
434
  var modalFlashes = $(this).find('.flash_messages');
428
- $(event.target).modal('hide');
435
+ Blacklight.modal.hide(event.target);
429
436
  event.preventDefault();
430
437
  var mainFlashes = $('#main-flashes');
431
438
  mainFlashes.append(modalFlashes);
@@ -433,6 +440,22 @@ Blacklight.modal.checkCloseModal = function (event) {
433
440
  }
434
441
  };
435
442
 
443
+ Blacklight.modal.hide = function (el) {
444
+ if (bootstrap.Modal.VERSION >= "5") {
445
+ bootstrap.Modal.getOrCreateInstance(el).hide();
446
+ } else {
447
+ $(el || Blacklight.modal.modalSelector).modal('hide');
448
+ }
449
+ };
450
+
451
+ Blacklight.modal.show = function (el) {
452
+ if (bootstrap.Modal.VERSION >= "5") {
453
+ bootstrap.Modal.getOrCreateInstance(el).show();
454
+ } else {
455
+ $(el || Blacklight.modal.modalSelector).modal('show');
456
+ }
457
+ };
458
+
436
459
  Blacklight.onLoad(function () {
437
460
  Blacklight.modal.setupModal();
438
461
  });
@@ -443,9 +466,9 @@ Blacklight.doSearchContextBehavior = function () {
443
466
  return Blacklight.do_search_context_behavior();
444
467
  }
445
468
 
446
- const elements = document.querySelectorAll('a[data-context-href]'); // Equivalent to Array.from(), but supports ie11
469
+ var elements = document.querySelectorAll('a[data-context-href]'); // Equivalent to Array.from(), but supports ie11
447
470
 
448
- const nodes = Array.prototype.slice.call(elements);
471
+ var nodes = Array.prototype.slice.call(elements);
449
472
  nodes.forEach(function (element) {
450
473
  element.addEventListener('click', function (e) {
451
474
  Blacklight.handleSearchContextMethod.call(e.currentTarget, e);
@@ -453,9 +476,17 @@ Blacklight.doSearchContextBehavior = function () {
453
476
  });
454
477
  };
455
478
 
456
- Blacklight.csrfToken = () => document.querySelector('meta[name=csrf-token]')?.content;
479
+ Blacklight.csrfToken = function () {
480
+ var _document$querySelect;
481
+
482
+ return (_document$querySelect = document.querySelector('meta[name=csrf-token]')) === null || _document$querySelect === void 0 ? void 0 : _document$querySelect.content;
483
+ };
484
+
485
+ Blacklight.csrfParam = function () {
486
+ var _document$querySelect2;
457
487
 
458
- Blacklight.csrfParam = () => document.querySelector('meta[name=csrf-param]')?.content; // this is the Rails.handleMethod with a couple adjustments, described inline:
488
+ return (_document$querySelect2 = document.querySelector('meta[name=csrf-param]')) === null || _document$querySelect2 === void 0 ? void 0 : _document$querySelect2.content;
489
+ }; // this is the Rails.handleMethod with a couple adjustments, described inline:
459
490
  // first, we're attaching this directly to the event handler, so we can check for meta-keys
460
491
 
461
492
 
@@ -467,22 +498,21 @@ Blacklight.handleSearchContextMethod = function (event) {
467
498
 
468
499
  var link = this; // instead of using the normal href, we need to use the context href instead
469
500
 
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');
501
+ var href = link.getAttribute('data-context-href');
502
+ var target = link.getAttribute('target');
503
+ var csrfToken = Blacklight.csrfToken();
504
+ var csrfParam = Blacklight.csrfParam();
505
+ var form = document.createElement('form');
475
506
  form.method = 'post';
476
507
  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
508
+ 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
509
 
480
510
  if (event.metaKey || event.ctrlKey) {
481
511
  target = '_blank';
482
512
  }
483
513
 
484
514
  if (csrfParam !== undefined && csrfToken !== undefined) {
485
- formContent += `<input name="${csrfParam}" value="${csrfToken}" type="hidden" />`;
515
+ formContent += "<input name=\"".concat(csrfParam, "\" value=\"").concat(csrfToken, "\" type=\"hidden\" />");
486
516
  } // Must trigger submit by click on a button, else "submit" event handler won't work!
487
517
  // https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/submit
488
518
 
@@ -1,6 +1,8 @@
1
1
  .constraints-container {
2
2
  @extend .mb-2;
3
- @extend .d-flex;
3
+ display: flex;
4
+ flex-wrap: wrap;
5
+ gap: 0.5rem 0.25rem;
4
6
  }
5
7
 
6
8
  .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)
@@ -90,7 +86,7 @@ module Blacklight
90
86
  end
91
87
 
92
88
  def facet_item_presenter(facet_config, facet_item, facet_field)
93
- Blacklight::FacetItemPresenter.new(facet_item, facet_config, @view_context, facet_field)
89
+ (facet_config.item_presenter || Blacklight::FacetItemPresenter).new(facet_item, facet_config, @view_context, facet_field)
94
90
  end
95
91
 
96
92
  def inclusive_facet_item_presenter(facet_config, facet_item, facet_field)
@@ -17,7 +17,7 @@ module Blacklight
17
17
  return to_enum(:presenters) unless block_given?
18
18
 
19
19
  @facet_field.paginator.items.each do |item|
20
- yield Blacklight::FacetItemPresenter.new(item, @facet_field.facet_field, @view_context, @facet_field.key, @facet_field.search_state)
20
+ yield (@facet_field.facet_field.item_presenter || Blacklight::FacetItemPresenter).new(item, @facet_field.facet_field, @view_context, @facet_field.key, @facet_field.search_state)
21
21
  end
22
22
  end
23
23
  end
@@ -78,7 +78,7 @@ module Blacklight
78
78
  end
79
79
 
80
80
  def facet_item_presenter(facet_item)
81
- Blacklight::FacetItemPresenter.new(facet_item, @facet_item.facet_config, @view_context, @facet_item.facet_field, @facet_item.search_state)
81
+ (@facet_item.facet_config.item_presenter || Blacklight::FacetItemPresenter).new(facet_item, @facet_item.facet_config, @view_context, @facet_item.facet_field, @facet_item.search_state)
82
82
  end
83
83
  end
84
84
  end
@@ -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
@@ -319,7 +319,7 @@ module Blacklight::FacetsHelperBehavior
319
319
  end
320
320
 
321
321
  def facet_item_presenter(facet_config, facet_item, facet_field)
322
- Blacklight::FacetItemPresenter.new(facet_item, facet_config, self, facet_field)
322
+ (facet_config.item_presenter || Blacklight::FacetItemPresenter).new(facet_item, facet_config, self, facet_field)
323
323
  end
324
324
 
325
325
  def facet_item_component(facet_config, facet_item, facet_field, **args)
@@ -9,7 +9,10 @@ module Blacklight::RenderPartialsHelperBehavior
9
9
  # @param [Hash] locals to pass to the render call
10
10
  # @return [String]
11
11
  def render_document_index documents = nil, locals = {}
12
- documents ||= @response.documents
12
+ unless documents
13
+ Deprecation.warn(self, "Calling render_document_index without documents is deprecated and will be removed in version 8")
14
+ documents = @response.documents
15
+ end
13
16
  render_document_index_with_view(document_index_view_type, documents, locals)
14
17
  end
15
18
 
@@ -1,4 +1,4 @@
1
- Blacklight = function() {
1
+ const Blacklight = function() {
2
2
  var buffer = new Array;
3
3
  return {
4
4
  onLoad: function(func) {
@@ -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,8 +43,12 @@ 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')
47
51
  elem.classList.add('js')
48
52
  })
53
+
54
+ window.Blacklight = Blacklight
@@ -114,13 +114,13 @@ Blacklight.modal.onFailure = function(jqXHR, textStatus, errorThrown) {
114
114
  this.type + ' ' + this.url + "\n" + jqXHR.status + ': ' + errorThrown +
115
115
  '</pre></div>';
116
116
  $(Blacklight.modal.modalSelector).find('.modal-content').html(contents);
117
- $(Blacklight.modal.modalSelector).modal('show');
117
+ Blacklight.modal.show();
118
118
  }
119
119
 
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) {
@@ -135,7 +135,7 @@ Blacklight.modal.receiveAjax = function (contents) {
135
135
  // if they did preventDefault, don't show the dialog
136
136
  if (e.isDefaultPrevented()) return;
137
137
 
138
- $(Blacklight.modal.modalSelector).modal('show');
138
+ Blacklight.modal.show();
139
139
  };
140
140
 
141
141
 
@@ -196,7 +196,7 @@ Blacklight.modal.checkCloseModal = function(event) {
196
196
  if ($(event.target).find(Blacklight.modal.modalCloseSelector).length) {
197
197
  var modalFlashes = $(this).find('.flash_messages');
198
198
 
199
- $(event.target).modal('hide');
199
+ Blacklight.modal.hide(event.target);
200
200
  event.preventDefault();
201
201
 
202
202
  var mainFlashes = $('#main-flashes');
@@ -205,6 +205,22 @@ Blacklight.modal.checkCloseModal = function(event) {
205
205
  }
206
206
  }
207
207
 
208
+ Blacklight.modal.hide = function(el) {
209
+ if (bootstrap.Modal.VERSION >= "5") {
210
+ bootstrap.Modal.getOrCreateInstance(el).hide();
211
+ } else {
212
+ $(el || Blacklight.modal.modalSelector).modal('hide');
213
+ }
214
+ }
215
+
216
+ Blacklight.modal.show = function(el) {
217
+ if (bootstrap.Modal.VERSION >= "5") {
218
+ bootstrap.Modal.getOrCreateInstance(el).show();
219
+ } else {
220
+ $(el || Blacklight.modal.modalSelector).modal('show');
221
+ }
222
+ }
223
+
208
224
  Blacklight.onLoad(function() {
209
225
  Blacklight.modal.setupModal();
210
226
  });
@@ -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)
@@ -14,7 +14,7 @@
14
14
  <%= render 'sort_and_per_page' %>
15
15
  <%= render partial: 'tools', locals: { document_list: @response.documents } %>
16
16
  <h2 class='section-heading sr-only visually-hidden'><%= t('blacklight.bookmarks.list_title') %></h2>
17
- <%= render_document_index %>
17
+ <%= render_document_index @response.documents %>
18
18
  <%= render 'results_pagination' %>
19
19
  <% end %>
20
20
  </div>
@@ -26,7 +26,7 @@
26
26
  <%- elsif render_grouped_response? %>
27
27
  <%= Deprecation.silence(Blacklight::RenderPartialsHelperBehavior) { render_grouped_document_index } %>
28
28
  <%- else %>
29
- <%= render_document_index %>
29
+ <%= render_document_index @response.documents %>
30
30
  <%- end %>
31
31
 
32
32
  <%= render 'results_pagination' %>