diff --git a/.rubocop.yml b/.rubocop.yml
index a849dd007..f43923c7f 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -17,6 +17,7 @@ AllCops:
- "config/**/*"
- "vendor/**/*"
- "spec/fixtures/**/*"
+ - "node_modules/**/*"
Rails:
Enabled: true
diff --git a/Gemfile b/Gemfile
index c0bc7809e..18e251b3b 100644
--- a/Gemfile
+++ b/Gemfile
@@ -136,3 +136,5 @@ gem 'recaptcha', '~> 5.17.1'
gem 'rack-attack'
gem 'cssbundling-rails', '~> 1.4'
+
+gem 'jsbundling-rails', '~> 1.3'
diff --git a/Gemfile.lock b/Gemfile.lock
index f0836b04b..fbe6f8876 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -450,6 +450,8 @@ GEM
rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0)
thor (>= 0.14, < 2.0)
+ jsbundling-rails (1.3.1)
+ railties (>= 6.0.0)
json (2.9.0)
jsonpath (1.1.5)
multi_json
@@ -931,6 +933,7 @@ DEPENDENCIES
iiif-presentation
jbuilder (~> 2.7)
jquery-rails
+ jsbundling-rails (~> 1.3)
jsonpath
letter_opener
listen (~> 3.3)
diff --git a/Procfile.dev b/Procfile.dev
index 18f64d232..6e11fb626 100644
--- a/Procfile.dev
+++ b/Procfile.dev
@@ -1,2 +1,3 @@
web: env RUBY_DEBUG_OPEN=true bin/rails server
css: yarn watch:css
+js: yarn build --watch
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
deleted file mode 100644
index 2661203dc..000000000
--- a/app/assets/javascripts/application.js
+++ /dev/null
@@ -1,39 +0,0 @@
-// This is a manifest file that'll be compiled into application.js, which will include all the files
-// listed below.
-//
-// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
-// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
-//
-// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
-// compiled file.
-//
-// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
-// about supported directives.
-//
-//= require jquery3
-//= require 'honeybadger'
-
-//= require rails-ujs
-//= require turbolinks
-//
-// Required by Blacklight
-//= require blacklight/blacklight
-
-//= require popper
-//= require twitter/typeahead
-//= require bootstrap
-
-//= require bibliography
-//= require cited_documents
-//= require blacklight_gallery
-//= require blacklight_heatmaps
-//= require blacklight_oembed
-//= require full_text_collapse
-//= require index_status_typeahead
-//= require exhibit_search_typeahead
-//= require nested_related_items
-//= require openseadragon
-//= require spotlight
-//= require table_of_contents
-//= require site_search_type_toggle
-//= require blacklight_heatmaps_overrides
diff --git a/app/assets/javascripts/bibliography.js b/app/assets/javascripts/bibliography.js
deleted file mode 100644
index 3d0d80bbf..000000000
--- a/app/assets/javascripts/bibliography.js
+++ /dev/null
@@ -1,110 +0,0 @@
-/* eslint-disable camelcase */
-/* global Bibliography */
-
-(function (global) {
- var Bibliography;
-
- Bibliography = {
- options: { toggleThreshold: 5, toggleIndex: 2 },
-
- init: function (el) {
- var _this = this;
- var $el = $(el);
- var data = $el.data();
-
- if (el.dataset.initialized) {
- const toggleButton = $el.find('.bibliography-button');
- if (toggleButton.length > 0) {
- this.bindToggleButtonHandler(toggleButton);
- }
- return;
- }
-
- $.getJSON(data.path, {
- 'f[related_document_id_ssim][]': data.parentid,
- 'f[format_main_ssim][]': 'Reference',
- sort: data.sort,
- format: 'json',
- rows: '1000'
- }, function (response) {
- var docTotal = response.data.length;
- if (docTotal > 0) {
- el.dataset.initialized = true;
- $el.show();
- var bibliographyList = $el.find('.bibliography-list');
-
- for (var i = 0; i < docTotal; i++) {
- var bibEntry = response.data[i];
- var html = _this.bibliographyItemTemplate(
- bibEntry, data.path, i, docTotal
- );
- bibliographyList.append(html);
- }
-
- if (docTotal > _this.options.toggleThreshold) {
- bibliographyList.append(_this.toggleButton());
- }
- }
- });
- },
-
- bibliographyItemTemplate: function(bibEntry, path, index, total) {
- var elClass = 'bibliography-body';
- var toggleIndex = this.options.toggleIndex;
- var toggleThreshold = this.options.toggleThreshold;
-
- if (index > toggleIndex && total > toggleThreshold) {
- elClass += ' hide-bibliography';
- }
-
- // This string contains the formatted bibliography for this item.
- // This string can contain HTML elements as well which should be displayed correctly.
- var formatted_bibliography = bibEntry.attributes.formatted_bibliography_ts.attributes.value;
-
- return '
' +
- formatted_bibliography +
- ' ' +
- '[View full reference]' +
- '' +
- '
';
- },
-
- bindToggleButtonHandler: function(button) {
- button.on('click', function() {
- var bibliosToToggle = button.parent().find('.hide-bibliography');
- var hidden = bibliosToToggle.first().is(':hidden');
- bibliosToToggle.toggle();
-
- if(hidden) {
- button.find('[data-behavior="text"]').text('Collapse bibliography');
- button.addClass('bibliography-expanded');
- } else {
- button.find('[data-behavior="text"]').text('Expand bibliography');
- button.removeClass('bibliography-expanded');
- }
- });
- },
-
- toggleButton: function() {
- var button = $(
- ''
- );
-
- this.bindToggleButtonHandler(button);
- return button;
- }
- };
-
- global.Bibliography = Bibliography;
-}(this));
-
-Blacklight.onLoad(function () {
- 'use strict';
-
- $('[data-behavior="bibliography-contents"]').each(function (i, element) {
- Bibliography.init(element); // eslint-disable-line no-undef
- });
-});
diff --git a/app/assets/javascripts/blacklight_gallery.js b/app/assets/javascripts/blacklight_gallery.js
deleted file mode 100644
index 992a7d4df..000000000
--- a/app/assets/javascripts/blacklight_gallery.js
+++ /dev/null
@@ -1 +0,0 @@
-//= require blacklight_gallery/default
\ No newline at end of file
diff --git a/app/assets/javascripts/blacklight_heatmaps.js b/app/assets/javascripts/blacklight_heatmaps.js
deleted file mode 100644
index ab7416596..000000000
--- a/app/assets/javascripts/blacklight_heatmaps.js
+++ /dev/null
@@ -1 +0,0 @@
-//= require blacklight_heatmaps/default
diff --git a/app/assets/javascripts/cited_documents.js b/app/assets/javascripts/cited_documents.js
deleted file mode 100644
index 6c75eac58..000000000
--- a/app/assets/javascripts/cited_documents.js
+++ /dev/null
@@ -1,44 +0,0 @@
-/* eslint-disable camelcase */
-/* global CitedDocuments */
-/* global Blacklight */
-
-(function (global) {
- var CitedDocuments;
-
- CitedDocuments = {
- init: function (el) {
- var $el = $(el);
- const citedDocList = $el.find('.cited-documents-list');
- // Prevent repeat script run on page back
- if (citedDocList[0].innerHTML != '') return;
-
- var data = $el.data();
- var queryIds = data.documentids.join(' ');
-
-
- $.post(data.path, {
- ids: queryIds,
- format: 'json',
- }, function (response) {
- response.forEach(function(citedDocEntry) {
- var html = '' +
- ' ' +
- citedDocEntry['title_display'] +
- '' +
- '';
- citedDocList.append(html);
- });
- });
- }
- };
-
- global.CitedDocuments = CitedDocuments;
-}(this));
-
-Blacklight.onLoad(function () {
- 'use strict';
-
- $('[data-behavior="cited-documents-contents"]').each(function (i, element) {
- CitedDocuments.init(element); // eslint-disable-line no-undef
- });
-});
diff --git a/app/assets/javascripts/exhibit_search_typeahead.js b/app/assets/javascripts/exhibit_search_typeahead.js
deleted file mode 100644
index c46002d26..000000000
--- a/app/assets/javascripts/exhibit_search_typeahead.js
+++ /dev/null
@@ -1,53 +0,0 @@
-/* global Blacklight */
-/* global Bloodhound */
-/* global ExhibitSearchTypeahead */
-
-(function (global) {
- var ExhibitSearchTypeahead;
-
- ExhibitSearchTypeahead = {
- form: null,
- typeaheadElement: null,
- typeaheadElementInput: null,
-
- init: function (el) {
- var _this = this;
- _this.typeaheadElement = el.closest('auto-complete');
- _this.typeaheadElementInput = el;
- _this.form = el.closest('form');
- _this.preventFormSubmitOnTypeahead();
-
- _this.typeaheadElement.addEventListener('auto-complete-change', function(e) {
- const slug = e.relatedTarget.value;
-
- if (!slug) return;
-
- e.relatedTarget.value = _this.getTitleFromSlug(slug);
- window.location = '/' + slug;
- });
- },
-
- preventFormSubmitOnTypeahead: function() {
- this.form.addEventListener('submit', (e) => {
- if (document.activeElement === this.typeaheadElementInput) {
- e.preventDefault();
- }
- });
- },
-
- getTitleFromSlug: function(slug) {
- const option = this.typeaheadElement.querySelector(`[data-autocomplete-value="${slug}"][role="option"]`);
- return option.dataset.autocompleteTitle;
- }
- };
-
- global.ExhibitSearchTypeahead = ExhibitSearchTypeahead;
-}(this));
-
-Blacklight.onLoad(function () {
- 'use strict';
-
- document.querySelectorAll('[data-behavior="exhibit-search-typeahead"]').forEach((element) => {
- ExhibitSearchTypeahead.init(element);
- });
-});
diff --git a/app/assets/javascripts/index_status_typeahead.js b/app/assets/javascripts/index_status_typeahead.js
deleted file mode 100644
index 12d32313c..000000000
--- a/app/assets/javascripts/index_status_typeahead.js
+++ /dev/null
@@ -1,86 +0,0 @@
-/* global Blacklight */
-/* global Bloodhound */
-/* global IndexStatusTypeahead */
-
-(function (global) {
- var IndexStatusTypeahead;
-
- IndexStatusTypeahead = {
- itemStatusRemoteUrl: null,
-
- indexStatusTable: function() {
- return $('[data-behavior="index-status-typeahead-table"]');
- },
-
- init: function (el) {
- var _this = this;
- const completer = el.closest('auto-complete');
- _this.itemStatusRemoteUrl = completer.dataset.typeaheadRemoteUrl;
-
- completer.addEventListener('submit', function(e) {
- e.preventDefault();
- });
-
- completer.addEventListener('auto-complete-change', function(e) {
- const option = completer.querySelector(`[data-autocomplete-value="${e.relatedTarget.value}"][role="option"]`);
- if (option) {
- _this.addIndexStatusRow(option.dataset.autocompleteValue);
- }
- });
- },
-
- addIndexStatusRow: function(druid) {
- if(this.indexStatusRow(druid).length > 0) {
- return; // Return if there is already an index status row present
- }
-
- this.indexStatusTable().show(); // Ensure the table is shown
- this.indexStatusTable().find('tbody').append(
- [
- '',
- '' + druid + ' | ',
- ' | ',
- '
'
- ].join('\n')
- );
-
- this.updateItemIndexStatus(druid);
- },
-
- // Getter for an index status row given a druid
- indexStatusRow: function(druid) {
- return $('tr[data-index-status-id="' + druid + '"]');
- },
-
- updateItemIndexStatus: function(druid) {
- var _this = this;
- $.ajax({ url: _this.itemStatusRemoteUrl + '/' + druid })
- .done(function(data) {
- var row = _this.indexStatusRow(druid);
-
- if (!data.status.ok) {
- row.addClass('danger');
- }
-
- var itemStatusCell = row.find('td[data-behavior="index-item-status"]');
- itemStatusCell.text(
- data.status.ok ? 'Published' : data.status.message
- );
- });
- },
-
- druids: function() {
- return $('[data-index-status-content]').data('index-status-content');
- },
- };
-
- global.IndexStatusTypeahead = IndexStatusTypeahead;
-}(this));
-
-Blacklight.onLoad(function () {
- 'use strict';
-
- document.querySelectorAll('[data-behavior="index-status-typeahead"]').forEach((element) => {
- IndexStatusTypeahead.init(element); // eslint-disable-line no-undef
- });
-});
diff --git a/app/assets/javascripts/nested_related_items.js b/app/assets/javascripts/nested_related_items.js
deleted file mode 100644
index 15b8219ee..000000000
--- a/app/assets/javascripts/nested_related_items.js
+++ /dev/null
@@ -1,103 +0,0 @@
-/* global Blacklight */
-/* global NestedRelatedItems */
-
-(function (global) {
- var NestedRelatedItems;
-
- NestedRelatedItems = {
- options: { itemSelector: 'li.mods_display_nested_related_item' },
- init: function (el) {
- var _this = this;
- var listItems = _this.listItems(el);
- listItems.each(function() {
- $(this).removeClass('open');
- _this.addToggleLink($(this));
- });
-
- if (listItems.has('dl').length > 0) {
- _this.addToggleAll(el);
- }
- },
-
- listItems: function(list) {
- return list.find(this.options.itemSelector);
- },
-
- addToggleAll: function(content) {
- // find the preceding
- var title = $(content).parents('dd').prev();
- var el = $('Expand all');
- this.toggleAll(el, content);
- title.append(el);
- },
-
- addToggleLink: function(content) {
- var dl = content.find('dl');
-
- if(dl.length > 0) {
- // Hide and remove the dl (so we can deal with just the text below)
- dl.hide();
- dl.detach();
- // Replace the content of the list item
- // with the current text wrapped in a link
- content.html(this.linkElement(content));
- // Add the dl back in
- content.append(dl);
- }
- },
-
- linkElement: function(content) {
- var _this = this;
- var link = $('' + content.text() + '');
- link.on('click', function() {
- _this.toggleMetadata($(this));
- });
-
- return link;
- },
-
- toggleAll: function(el, content) {
- var _this = this;
- el.on('click', function(){
- var toggleLink = $(this);
- toggleLink.toggleClass('open');
- toggleLink.text((toggleLink.text() == 'Collapse all') ? 'Expand all' : 'Collapse all');
- var links = _this.listItems(content);
-
- // Handle mixed lists of open / closed items
- if (toggleLink.hasClass('open')){
- links = links.not('.open').find('a');
- } else {
- links = links.filter($('.open')).find('a');
- }
- links.each(function(){
- _this.toggleMetadata($(this));
- });
- });
- },
-
- toggleMetadata: function(item) {
- var listItem = item.parent('li');
- listItem.toggleClass('open');
- listItem.find('dl').toggle();
- }
- };
-
- global.NestedRelatedItems = NestedRelatedItems;
-}(this));
-
-Blacklight.onLoad(function () {
- 'use strict';
-
- // Load JS in Bootstrap modal
- document.querySelector('#blacklight-modal').addEventListener('loaded.blacklight.blacklight-modal', function (e) {
- $('.mods_display_nested_related_items').each(function (i, element) {
- NestedRelatedItems.init($(element)); // eslint-disable-line no-undef
- });
- });
-
- // Metadata page
- $('.mods_display_nested_related_items').each(function (i, element) {
- NestedRelatedItems.init($(element)); // eslint-disable-line no-undef
- });
-});
diff --git a/app/assets/javascripts/openseadragon.js b/app/assets/javascripts/openseadragon.js
deleted file mode 100644
index 2ab91a9f1..000000000
--- a/app/assets/javascripts/openseadragon.js
+++ /dev/null
@@ -1,2 +0,0 @@
-//= require openseadragon/openseadragon
-//= require openseadragon/rails
\ No newline at end of file
diff --git a/app/assets/javascripts/site_search_type_toggle.js b/app/assets/javascripts/site_search_type_toggle.js
deleted file mode 100644
index 9922ef123..000000000
--- a/app/assets/javascripts/site_search_type_toggle.js
+++ /dev/null
@@ -1,47 +0,0 @@
-/* global Blacklight */
-/* global SiteSearchTypeToggle */
-
-(function (global) {
- var SiteSearchTypeToggle;
-
- SiteSearchTypeToggle = {
- menuOptions: [],
- init: function (el) {
- var _this = this;
- var button = el.find('button.dropdown-toggle');
- var menuItems = el.find('.dropdown-menu .dropdown-item');
- _this.menuOptions = $('[data-behavior="site-search-type"]');
- _this.hideAllMenuOptions();
- el.show();
-
- $(el.data('enabled')).show();
-
- menuItems.each(function() {
- $(this).on('click', function(e) {
- e.preventDefault();
-
- _this.hideAllMenuOptions();
- $($(this).data('bs-target')).show();
-
- button.text($(this).data('buttonText'));
- });
- });
- },
-
- hideAllMenuOptions: function() {
- this.menuOptions.each(function() {
- $(this).hide();
- });
- }
- };
-
- global.SiteSearchTypeToggle = SiteSearchTypeToggle;
-}(this));
-
-Blacklight.onLoad(function () {
- 'use strict';
-
- $('[data-behavior="site-search-type-toggle"]').each(function (i, element) {
- SiteSearchTypeToggle.init($(element)); // eslint-disable-line no-undef
- });
-});
diff --git a/app/javascript/application.js b/app/javascript/application.js
new file mode 100644
index 000000000..efb998c00
--- /dev/null
+++ b/app/javascript/application.js
@@ -0,0 +1,30 @@
+// Entry point for the build script in your package.json
+
+//= require rails-ujs
+//= require turbolinks
+//
+// Required by Blacklight
+import './blacklight'
+import './sir_trevor'
+
+import "spotlight-frontend/app/assets/javascripts/spotlight/spotlight.esm.js";
+import githubAutoCompleteElement from "@github/auto-complete-element";
+
+import './bibliography'
+import './cited_documents'
+import 'blacklight-gallery/vendor/assets/javascripts/imagesloaded.pkgd.js'
+import 'blacklight-gallery/app/assets/javascripts/blacklight_gallery/slideshow'
+import 'blacklight-gallery/app/assets/javascripts/blacklight_gallery/masonry'
+
+import './blacklight_heatmaps'
+
+
+import 'blacklight-oembed'
+import './full_text_collapse'
+import './index_status_typeahead'
+import './exhibit_search_typeahead'
+import './nested_related_items'
+import 'openseadragon-rails'
+import './table_of_contents'
+import './site_search_type_toggle'
+import './blacklight_heatmaps_overrides'
diff --git a/app/javascript/bibliography.js b/app/javascript/bibliography.js
new file mode 100644
index 000000000..29ad27e6a
--- /dev/null
+++ b/app/javascript/bibliography.js
@@ -0,0 +1,103 @@
+/* eslint-disable camelcase */
+
+const Bibliography = {
+ options: { toggleThreshold: 5, toggleIndex: 2 },
+
+ init: function (el) {
+ var _this = this;
+ var $el = $(el);
+ var data = $el.data();
+
+ if (el.dataset.initialized) {
+ const toggleButton = $el.find('.bibliography-button');
+ if (toggleButton.length > 0) {
+ this.bindToggleButtonHandler(toggleButton);
+ }
+ return;
+ }
+
+ $.getJSON(data.path, {
+ 'f[related_document_id_ssim][]': data.parentid,
+ 'f[format_main_ssim][]': 'Reference',
+ sort: data.sort,
+ format: 'json',
+ rows: '1000'
+ }, function (response) {
+ var docTotal = response.data.length;
+ if (docTotal > 0) {
+ el.dataset.initialized = true;
+ $el.show();
+ var bibliographyList = $el.find('.bibliography-list');
+
+ for (var i = 0; i < docTotal; i++) {
+ var bibEntry = response.data[i];
+ var html = _this.bibliographyItemTemplate(
+ bibEntry, data.path, i, docTotal
+ );
+ bibliographyList.append(html);
+ }
+
+ if (docTotal > _this.options.toggleThreshold) {
+ bibliographyList.append(_this.toggleButton());
+ }
+ }
+ });
+ },
+
+ bibliographyItemTemplate: function(bibEntry, path, index, total) {
+ var elClass = 'bibliography-body';
+ var toggleIndex = this.options.toggleIndex;
+ var toggleThreshold = this.options.toggleThreshold;
+
+ if (index > toggleIndex && total > toggleThreshold) {
+ elClass += ' hide-bibliography';
+ }
+
+ // This string contains the formatted bibliography for this item.
+ // This string can contain HTML elements as well which should be displayed correctly.
+ var formatted_bibliography = bibEntry.attributes.formatted_bibliography_ts.attributes.value;
+
+ return '' +
+ formatted_bibliography +
+ ' ' +
+ '[View full reference]' +
+ '' +
+ '
';
+ },
+
+ bindToggleButtonHandler: function(button) {
+ button.on('click', function() {
+ var bibliosToToggle = button.parent().find('.hide-bibliography');
+ var hidden = bibliosToToggle.first().is(':hidden');
+ bibliosToToggle.toggle();
+
+ if(hidden) {
+ button.find('[data-behavior="text"]').text('Collapse bibliography');
+ button.addClass('bibliography-expanded');
+ } else {
+ button.find('[data-behavior="text"]').text('Expand bibliography');
+ button.removeClass('bibliography-expanded');
+ }
+ });
+ },
+
+ toggleButton: function() {
+ var button = $(
+ ''
+ );
+
+ this.bindToggleButtonHandler(button);
+ return button;
+ }
+};
+
+Blacklight.onLoad(function () {
+ 'use strict';
+
+ $('[data-behavior="bibliography-contents"]').each(function (i, element) {
+ Bibliography.init(element); // eslint-disable-line no-undef
+ });
+});
diff --git a/app/javascript/blacklight.js b/app/javascript/blacklight.js
new file mode 100644
index 000000000..71003e9d8
--- /dev/null
+++ b/app/javascript/blacklight.js
@@ -0,0 +1,2 @@
+import Blacklight from "blacklight-frontend";
+window.Blacklight = Blacklight
diff --git a/app/javascript/blacklight_heatmaps.js b/app/javascript/blacklight_heatmaps.js
new file mode 100644
index 000000000..a7d5ff076
--- /dev/null
+++ b/app/javascript/blacklight_heatmaps.js
@@ -0,0 +1,6 @@
+import 'blacklight-heatmaps/vendor/assets/javascripts/leaflet_solr_heatmap'
+import BlacklightHeatmaps from 'blacklight-heatmaps/app/assets/javascripts/blacklight_heatmaps/blacklight_heatmaps'
+import 'blacklight-heatmaps/app/assets/javascripts/blacklight_heatmaps/basemaps'
+import 'blacklight-heatmaps/app/assets/javascripts/blacklight_heatmaps/icons'
+import 'blacklight-heatmaps/app/assets/javascripts/blacklight_heatmaps/viewers/index'
+import 'blacklight-heatmaps/app/assets/javascripts/blacklight_heatmaps/viewers/show'
diff --git a/app/assets/javascripts/blacklight_heatmaps_overrides.js b/app/javascript/blacklight_heatmaps_overrides.js
similarity index 100%
rename from app/assets/javascripts/blacklight_heatmaps_overrides.js
rename to app/javascript/blacklight_heatmaps_overrides.js
diff --git a/app/assets/javascripts/blacklight_oembed.js b/app/javascript/blacklight_oembed.js
similarity index 100%
rename from app/assets/javascripts/blacklight_oembed.js
rename to app/javascript/blacklight_oembed.js
diff --git a/app/javascript/cited_documents.js b/app/javascript/cited_documents.js
new file mode 100644
index 000000000..0336c2689
--- /dev/null
+++ b/app/javascript/cited_documents.js
@@ -0,0 +1,36 @@
+/* global Blacklight */
+
+const CitedDocuments = {
+ init: function (el) {
+ var $el = $(el);
+ const citedDocList = $el.find('.cited-documents-list');
+ // Prevent repeat script run on page back
+ if (citedDocList[0].innerHTML != '') return;
+
+ var data = $el.data();
+ var queryIds = data.documentids.join(' ');
+
+
+ $.post(data.path, {
+ ids: queryIds,
+ format: 'json',
+ }, function (response) {
+ response.forEach(function(citedDocEntry) {
+ var html = '' +
+ ' ' +
+ citedDocEntry['title_display'] +
+ '' +
+ '';
+ citedDocList.append(html);
+ });
+ });
+ }
+};
+
+Blacklight.onLoad(function () {
+ 'use strict';
+
+ $('[data-behavior="cited-documents-contents"]').each(function (i, element) {
+ CitedDocuments.init(element); // eslint-disable-line no-undef
+ });
+});
diff --git a/app/javascript/exhibit_search_typeahead.js b/app/javascript/exhibit_search_typeahead.js
new file mode 100644
index 000000000..7b1fec40a
--- /dev/null
+++ b/app/javascript/exhibit_search_typeahead.js
@@ -0,0 +1,45 @@
+/* global Blacklight */
+
+const ExhibitSearchTypeahead = {
+ form: null,
+ typeaheadElement: null,
+ typeaheadElementInput: null,
+
+ init: function (el) {
+ var _this = this;
+ _this.typeaheadElement = el.closest('auto-complete');
+ _this.typeaheadElementInput = el;
+ _this.form = el.closest('form');
+ _this.preventFormSubmitOnTypeahead();
+
+ _this.typeaheadElement.addEventListener('auto-complete-change', function(e) {
+ const slug = e.relatedTarget.value;
+
+ if (!slug) return;
+
+ e.relatedTarget.value = _this.getTitleFromSlug(slug);
+ window.location = '/' + slug;
+ });
+ },
+
+ preventFormSubmitOnTypeahead: function() {
+ this.form.addEventListener('submit', (e) => {
+ if (document.activeElement === this.typeaheadElementInput) {
+ e.preventDefault();
+ }
+ });
+ },
+
+ getTitleFromSlug: function(slug) {
+ const option = this.typeaheadElement.querySelector(`[data-autocomplete-value="${slug}"][role="option"]`);
+ return option.dataset.autocompleteTitle;
+ }
+};
+
+Blacklight.onLoad(function () {
+ 'use strict';
+
+ document.querySelectorAll('[data-behavior="exhibit-search-typeahead"]').forEach((element) => {
+ ExhibitSearchTypeahead.init(element);
+ });
+});
diff --git a/app/assets/javascripts/full_text_collapse.js b/app/javascript/full_text_collapse.js
similarity index 100%
rename from app/assets/javascripts/full_text_collapse.js
rename to app/javascript/full_text_collapse.js
diff --git a/app/javascript/index_status_typeahead.js b/app/javascript/index_status_typeahead.js
new file mode 100644
index 000000000..ea7623193
--- /dev/null
+++ b/app/javascript/index_status_typeahead.js
@@ -0,0 +1,78 @@
+/* global Blacklight */
+
+const IndexStatusTypeahead = {
+ itemStatusRemoteUrl: null,
+
+ indexStatusTable: function() {
+ return $('[data-behavior="index-status-typeahead-table"]');
+ },
+
+ init: function (el) {
+ var _this = this;
+ const completer = el.closest('auto-complete');
+ _this.itemStatusRemoteUrl = completer.dataset.typeaheadRemoteUrl;
+
+ completer.addEventListener('submit', function(e) {
+ e.preventDefault();
+ });
+
+ completer.addEventListener('auto-complete-change', function(e) {
+ const option = completer.querySelector(`[data-autocomplete-value="${e.relatedTarget.value}"][role="option"]`);
+ if (option) {
+ _this.addIndexStatusRow(option.dataset.autocompleteValue);
+ }
+ });
+ },
+
+ addIndexStatusRow: function(druid) {
+ if(this.indexStatusRow(druid).length > 0) {
+ return; // Return if there is already an index status row present
+ }
+
+ this.indexStatusTable().show(); // Ensure the table is shown
+ this.indexStatusTable().find('tbody').append(
+ [
+ '',
+ '' + druid + ' | ',
+ ' | ',
+ '
'
+ ].join('\n')
+ );
+
+ this.updateItemIndexStatus(druid);
+ },
+
+ // Getter for an index status row given a druid
+ indexStatusRow: function(druid) {
+ return $('tr[data-index-status-id="' + druid + '"]');
+ },
+
+ updateItemIndexStatus: function(druid) {
+ var _this = this;
+ $.ajax({ url: _this.itemStatusRemoteUrl + '/' + druid })
+ .done(function(data) {
+ var row = _this.indexStatusRow(druid);
+
+ if (!data.status.ok) {
+ row.addClass('danger');
+ }
+
+ var itemStatusCell = row.find('td[data-behavior="index-item-status"]');
+ itemStatusCell.text(
+ data.status.ok ? 'Published' : data.status.message
+ );
+ });
+ },
+
+ druids: function() {
+ return $('[data-index-status-content]').data('index-status-content');
+ },
+};
+
+Blacklight.onLoad(function () {
+ 'use strict';
+
+ document.querySelectorAll('[data-behavior="index-status-typeahead"]').forEach((element) => {
+ IndexStatusTypeahead.init(element); // eslint-disable-line no-undef
+ });
+});
diff --git a/app/javascript/nested_related_items.js b/app/javascript/nested_related_items.js
new file mode 100644
index 000000000..c88e8e280
--- /dev/null
+++ b/app/javascript/nested_related_items.js
@@ -0,0 +1,96 @@
+/* global Blacklight */
+
+const NestedRelatedItems = {
+ options: { itemSelector: 'li.mods_display_nested_related_item' },
+ init: function (el) {
+ var _this = this;
+ var listItems = _this.listItems(el);
+ listItems.each(function() {
+ $(this).removeClass('open');
+ _this.addToggleLink($(this));
+ });
+
+ if (listItems.has('dl').length > 0) {
+ _this.addToggleAll(el);
+ }
+ },
+
+ listItems: function(list) {
+ return list.find(this.options.itemSelector);
+ },
+
+ addToggleAll: function(content) {
+ // find the preceding
+ var title = $(content).parents('dd').prev();
+ var el = $('Expand all');
+ this.toggleAll(el, content);
+ title.append(el);
+ },
+
+ addToggleLink: function(content) {
+ var dl = content.find('dl');
+
+ if(dl.length > 0) {
+ // Hide and remove the dl (so we can deal with just the text below)
+ dl.hide();
+ dl.detach();
+ // Replace the content of the list item
+ // with the current text wrapped in a link
+ content.html(this.linkElement(content));
+ // Add the dl back in
+ content.append(dl);
+ }
+ },
+
+ linkElement: function(content) {
+ var _this = this;
+ var link = $('' + content.text() + '');
+ link.on('click', function() {
+ _this.toggleMetadata($(this));
+ });
+
+ return link;
+ },
+
+ toggleAll: function(el, content) {
+ var _this = this;
+ el.on('click', function(){
+ var toggleLink = $(this);
+ toggleLink.toggleClass('open');
+ toggleLink.text((toggleLink.text() == 'Collapse all') ? 'Expand all' : 'Collapse all');
+ var links = _this.listItems(content);
+
+ // Handle mixed lists of open / closed items
+ if (toggleLink.hasClass('open')){
+ links = links.not('.open').find('a');
+ } else {
+ links = links.filter($('.open')).find('a');
+ }
+ links.each(function(){
+ _this.toggleMetadata($(this));
+ });
+ });
+ },
+
+ toggleMetadata: function(item) {
+ var listItem = item.parent('li');
+ listItem.toggleClass('open');
+ listItem.find('dl').toggle();
+ }
+};
+
+Blacklight.onLoad(function () {
+ 'use strict';
+
+ // Load JS in Bootstrap modal
+ document.querySelector('#blacklight-modal').addEventListener('loaded.blacklight.blacklight-modal', function (e) {
+ $('.mods_display_nested_related_items').each(function (i, element) {
+ NestedRelatedItems.init($(element)); // eslint-disable-line no-undef
+ });
+ });
+
+ // Metadata page
+ $('.mods_display_nested_related_items').each(function (i, element) {
+ NestedRelatedItems.init($(element)); // eslint-disable-line no-undef
+ });
+});
diff --git a/app/javascript/sir_trevor.js b/app/javascript/sir_trevor.js
new file mode 100644
index 000000000..4946216c0
--- /dev/null
+++ b/app/javascript/sir_trevor.js
@@ -0,0 +1,2 @@
+import SirTrevor from 'sir-trevor'
+window.SirTrevor = SirTrevor
diff --git a/app/assets/javascripts/sir_trevor_block_overrides.js b/app/javascript/sir_trevor_block_overrides.js
similarity index 100%
rename from app/assets/javascripts/sir_trevor_block_overrides.js
rename to app/javascript/sir_trevor_block_overrides.js
diff --git a/app/javascript/site_search_type_toggle.js b/app/javascript/site_search_type_toggle.js
new file mode 100644
index 000000000..a398f8d00
--- /dev/null
+++ b/app/javascript/site_search_type_toggle.js
@@ -0,0 +1,40 @@
+/* global Blacklight */
+
+const SiteSearchTypeToggle = {
+ menuOptions: [],
+ init: function (el) {
+ var _this = this;
+ var button = el.find('button.dropdown-toggle');
+ var menuItems = el.find('.dropdown-menu .dropdown-item');
+ _this.menuOptions = $('[data-behavior="site-search-type"]');
+ _this.hideAllMenuOptions();
+ el.show();
+
+ $(el.data('enabled')).show();
+
+ menuItems.each(function() {
+ $(this).on('click', function(e) {
+ e.preventDefault();
+
+ _this.hideAllMenuOptions();
+ $($(this).data('bs-target')).show();
+
+ button.text($(this).data('buttonText'));
+ });
+ });
+ },
+
+ hideAllMenuOptions: function() {
+ this.menuOptions.each(function() {
+ $(this).hide();
+ });
+ }
+};
+
+Blacklight.onLoad(function () {
+ 'use strict';
+
+ $('[data-behavior="site-search-type-toggle"]').each(function (i, element) {
+ SiteSearchTypeToggle.init($(element)); // eslint-disable-line no-undef
+ });
+});
diff --git a/app/assets/javascripts/spotlight.js b/app/javascript/spotlight.js
similarity index 100%
rename from app/assets/javascripts/spotlight.js
rename to app/javascript/spotlight.js
diff --git a/app/assets/javascripts/table_of_contents.js b/app/javascript/table_of_contents.js
similarity index 100%
rename from app/assets/javascripts/table_of_contents.js
rename to app/javascript/table_of_contents.js
diff --git a/app/views/layouts/spotlight/base.html.erb b/app/views/layouts/spotlight/base.html.erb
index a3c1bb68c..fd1d6869a 100644
--- a/app/views/layouts/spotlight/base.html.erb
+++ b/app/views/layouts/spotlight/base.html.erb
@@ -18,7 +18,16 @@
<% end %>
<%= stylesheet_link_tag "component_library_overrides" %>
- <%= javascript_include_tag "application", async: Settings.async_javascript %>
+
+
+ <%= javascript_include_tag "application", "data-turbo-track": "reload", type: "module" %>
+