blacklight-spotlight 5.3.2 → 6.0.0.rc1

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 (181) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +20 -4
  3. data/Rakefile +1 -2
  4. data/app/assets/javascripts/spotlight/spotlight.esm.js +2168 -4560
  5. data/app/assets/javascripts/spotlight/spotlight.esm.js.map +1 -1
  6. data/app/assets/javascripts/spotlight/spotlight.js +2167 -4559
  7. data/app/assets/javascripts/spotlight/spotlight.js.map +1 -1
  8. data/app/assets/stylesheets/spotlight/_blacklight_overrides.scss +4 -0
  9. data/app/assets/stylesheets/spotlight/_browse.scss +0 -4
  10. data/app/assets/stylesheets/spotlight/{_collapse_toggle.scss → _collapse_toggle.css} +2 -2
  11. data/app/assets/stylesheets/spotlight/_exhibit_admin.scss +8 -0
  12. data/app/assets/stylesheets/spotlight/_exhibits_index.scss +2 -1
  13. data/app/assets/stylesheets/spotlight/_footer.scss +2 -2
  14. data/app/assets/stylesheets/spotlight/_header.scss +8 -8
  15. data/app/assets/stylesheets/spotlight/_pages.scss +1 -1
  16. data/app/assets/stylesheets/spotlight/_slideshow_block.scss +15 -0
  17. data/app/assets/stylesheets/spotlight/_spotlight.scss +1 -1
  18. data/app/assets/stylesheets/spotlight/_translations.scss +3 -3
  19. data/app/assets/stylesheets/spotlight/_uploaded_items_block.css +7 -0
  20. data/app/assets/stylesheets/spotlight/_variables.css +15 -0
  21. data/app/assets/stylesheets/spotlight/browse_group_categories_block.scss +0 -76
  22. data/app/components/blacklight/icons/pause_component.rb +15 -0
  23. data/app/components/blacklight/icons/play_arrow_component.rb +15 -0
  24. data/app/components/spotlight/analytics/dashboard_component.html.erb +1 -1
  25. data/app/components/spotlight/document_admin_table_component.html.erb +2 -2
  26. data/app/components/spotlight/masthead_component.html.erb +18 -0
  27. data/app/components/spotlight/masthead_component.rb +46 -0
  28. data/app/components/spotlight/save_search_component.html.erb +1 -1
  29. data/app/components/spotlight/solr_document_legacy_embed_component.html.erb +0 -4
  30. data/app/components/spotlight/solr_document_legacy_embed_component.rb +2 -2
  31. data/app/components/spotlight/tag_selector_component.html.erb +1 -1
  32. data/app/components/spotlight/tag_selector_component.rb +3 -2
  33. data/app/controllers/concerns/spotlight/controller.rb +15 -14
  34. data/app/controllers/concerns/spotlight/search_helper.rb +2 -5
  35. data/app/controllers/spotlight/browse_controller.rb +1 -2
  36. data/app/controllers/spotlight/catalog_controller.rb +1 -2
  37. data/app/controllers/spotlight/concerns/application_controller.rb +4 -6
  38. data/app/controllers/spotlight/exhibits_controller.rb +22 -10
  39. data/app/controllers/spotlight/lock_controller.rb +1 -1
  40. data/app/controllers/spotlight/pages_controller.rb +11 -11
  41. data/app/controllers/spotlight/resources_controller.rb +1 -1
  42. data/app/helpers/spotlight/application_helper.rb +14 -3
  43. data/app/helpers/spotlight/main_app_helpers.rb +2 -2
  44. data/app/javascript/spotlight/admin/add_another.js +37 -25
  45. data/app/javascript/spotlight/admin/add_image_selector.js +43 -26
  46. data/app/javascript/spotlight/admin/add_new_button.js +51 -36
  47. data/app/javascript/spotlight/admin/blacklight_configuration.js +76 -54
  48. data/app/javascript/spotlight/admin/block_mixins/autocompleteable.js +102 -101
  49. data/app/javascript/spotlight/admin/block_mixins/formable.js +91 -75
  50. data/app/javascript/spotlight/admin/block_mixins/plustextable.js +46 -48
  51. data/app/javascript/spotlight/admin/blocks/block.js +27 -28
  52. data/app/javascript/spotlight/admin/blocks/browse_block.js +14 -10
  53. data/app/javascript/spotlight/admin/blocks/browse_group_categories_block.js +14 -10
  54. data/app/javascript/spotlight/admin/blocks/pages_block.js +5 -4
  55. data/app/javascript/spotlight/admin/blocks/resources_block.js +61 -41
  56. data/app/javascript/spotlight/admin/blocks/search_result_block.js +24 -7
  57. data/app/javascript/spotlight/admin/blocks/solr_documents_base_block.js +103 -50
  58. data/app/javascript/spotlight/admin/blocks/solr_documents_carousel_block.js +50 -26
  59. data/app/javascript/spotlight/admin/blocks/solr_documents_features_block.js +47 -23
  60. data/app/javascript/spotlight/admin/blocks/uploaded_items_block.js +35 -19
  61. data/app/javascript/spotlight/admin/crop.js +146 -66
  62. data/app/javascript/spotlight/admin/croppable.js +5 -4
  63. data/app/javascript/spotlight/admin/croppable_modal.js +67 -32
  64. data/app/javascript/spotlight/admin/edit_in_place.js +69 -54
  65. data/app/javascript/spotlight/admin/exhibits.js +92 -45
  66. data/app/javascript/spotlight/admin/form_observer.js +92 -78
  67. data/app/javascript/spotlight/admin/multi_image_selector.js +201 -153
  68. data/app/javascript/spotlight/admin/pages.js +13 -7
  69. data/app/javascript/spotlight/admin/progress_monitor.js +65 -50
  70. data/app/javascript/spotlight/admin/readonly_checkbox.js +7 -3
  71. data/app/javascript/spotlight/admin/search_typeahead.js +20 -11
  72. data/app/javascript/spotlight/admin/select_related_input.js +23 -23
  73. data/app/javascript/spotlight/admin/serialize_json.js +120 -0
  74. data/app/javascript/spotlight/admin/sir-trevor/block_controls.js +24 -11
  75. data/app/javascript/spotlight/admin/sir-trevor/block_limits.js +9 -6
  76. data/app/javascript/spotlight/admin/sir-trevor/locales.js +2 -2
  77. data/app/javascript/spotlight/admin/spotlight_nestable.js +2 -5
  78. data/app/javascript/spotlight/admin/translation_progress.js +18 -13
  79. data/app/javascript/spotlight/admin/users.js +151 -64
  80. data/app/javascript/spotlight/user/carousel.js +104 -32
  81. data/app/javascript/spotlight/user/clear_form_button.js +24 -14
  82. data/app/javascript/spotlight/user/index.js +0 -2
  83. data/app/javascript/spotlight/user/zpr_links.js +99 -40
  84. data/app/jobs/concerns/spotlight/gather_documents.rb +1 -1
  85. data/app/jobs/spotlight/add_uploads_from_csv.rb +29 -8
  86. data/app/models/concerns/spotlight/access_controls_enforcement_search_builder.rb +13 -2
  87. data/app/models/concerns/spotlight/browse_category_search_builder.rb +3 -3
  88. data/app/models/concerns/spotlight/exhibit_documents.rb +2 -2
  89. data/app/models/concerns/spotlight/sitemap.rb +2 -2
  90. data/app/models/concerns/spotlight/solr_document/finder.rb +2 -2
  91. data/app/models/sir_trevor_rails/blocks/solr_documents_block.rb +2 -1
  92. data/app/models/spotlight/blacklight_configuration.rb +5 -3
  93. data/app/models/spotlight/contact_email.rb +2 -2
  94. data/app/models/spotlight/exhibit.rb +28 -0
  95. data/app/models/spotlight/featured_image.rb +1 -1
  96. data/app/models/spotlight/field_metadata.rb +10 -5
  97. data/app/models/spotlight/job_tracker.rb +2 -2
  98. data/app/models/spotlight/main_navigation.rb +2 -2
  99. data/app/models/spotlight/page.rb +3 -3
  100. data/app/models/spotlight/resources/iiif_harvester.rb +7 -4
  101. data/app/models/spotlight/resources/iiif_manifest_metadata.rb +1 -3
  102. data/app/models/spotlight/resources/iiif_service.rb +21 -6
  103. data/app/models/spotlight/search.rb +5 -5
  104. data/app/services/spotlight/bulk_updates_csv_template_service.rb +1 -1
  105. data/app/services/spotlight/etl/pipeline.rb +2 -2
  106. data/app/services/spotlight/etl/step.rb +2 -2
  107. data/app/views/catalog/_remove_tags.html.erb +2 -2
  108. data/app/views/layouts/spotlight/base.html.erb +3 -6
  109. data/app/views/layouts/spotlight/spotlight.html.erb +2 -2
  110. data/app/views/shared/_analytics.html.erb +4 -3
  111. data/app/views/shared/_masthead.html.erb +2 -18
  112. data/app/views/spotlight/about_pages/_empty.html.erb +1 -1
  113. data/app/views/spotlight/about_pages/_sidebar.html.erb +10 -8
  114. data/app/views/spotlight/browse/_search.html.erb +2 -2
  115. data/app/views/spotlight/browse/_search_box.html.erb +6 -14
  116. data/app/views/spotlight/browse/index.html.erb +1 -1
  117. data/app/views/spotlight/browse/show.html.erb +1 -1
  118. data/app/views/spotlight/catalog/_document_admin_table.html.erb +1 -1
  119. data/app/views/spotlight/catalog/edit.html.erb +1 -1
  120. data/app/views/spotlight/dashboards/_page.html.erb +1 -1
  121. data/app/views/spotlight/exhibits/_exhibit_card.html.erb +3 -1
  122. data/app/views/spotlight/exhibits/_export.html.erb +17 -1
  123. data/app/views/spotlight/exhibits/_form.html.erb +20 -4
  124. data/app/views/spotlight/exhibits/_missing_exhibits.html.erb +3 -3
  125. data/app/views/spotlight/exhibits/index.html.erb +21 -8
  126. data/app/views/spotlight/feature_pages/_empty.html.erb +1 -1
  127. data/app/views/spotlight/feature_pages/_sidebar.html.erb +17 -15
  128. data/app/views/spotlight/home_pages/_empty.html.erb +7 -7
  129. data/app/views/spotlight/pages/show.html.erb +1 -0
  130. data/app/views/spotlight/sir_trevor/blocks/_browse_group_categories_block.html.erb +5 -16
  131. data/app/views/spotlight/sir_trevor/blocks/_embedded_document.html.erb +3 -5
  132. data/app/views/spotlight/sir_trevor/blocks/_link_to_search_block.html.erb +1 -1
  133. data/app/views/spotlight/sir_trevor/blocks/_solr_documents_carousel_block.html.erb +11 -2
  134. data/app/views/spotlight/sites/_exhibit.html.erb +1 -1
  135. data/config/locales/spotlight.ar.yml +1 -2
  136. data/config/locales/spotlight.de.yml +1 -2
  137. data/config/locales/spotlight.en.yml +39 -6
  138. data/config/locales/spotlight.es.yml +1 -2
  139. data/config/locales/spotlight.fr.yml +1 -2
  140. data/config/locales/spotlight.it.yml +1 -2
  141. data/config/locales/spotlight.ja.yml +39 -0
  142. data/config/locales/spotlight.zh.yml +1 -2
  143. data/db/migrate/20261007133748_add_discovery_enabled_to_spotlight_exhibits.rb +5 -0
  144. data/lib/generators/spotlight/assets/importmap_generator.rb +2 -10
  145. data/lib/generators/spotlight/assets/propshaft_generator.rb +5 -4
  146. data/lib/generators/spotlight/install_generator.rb +2 -4
  147. data/lib/generators/spotlight/templates/catalog_controller.rb +0 -1
  148. data/lib/generators/spotlight/templates/config/initializers/spotlight_initializer.rb +18 -4
  149. data/lib/generators/spotlight/templates/solr/conf/schema.xml +4 -3
  150. data/lib/generators/spotlight/templates/solr/conf/solrconfig.xml +3 -8
  151. data/lib/migration/page_language.rb +0 -2
  152. data/lib/spotlight/engine.rb +23 -7
  153. data/lib/spotlight/search_state.rb +7 -11
  154. data/lib/spotlight/version.rb +1 -1
  155. data/lib/spotlight.rb +1 -1
  156. data/spec/support/features/capybara_wait_metadata_helper.rb +3 -1
  157. data/spec/support/features/test_features_helpers.rb +24 -1
  158. data/spec/support/iiif_manifest_fixtures.rb +33 -0
  159. data/spec/support/stub_dns_resolution.rb +12 -0
  160. metadata +38 -58
  161. data/app/assets/stylesheets/spotlight/_uploaded_items_block.scss +0 -7
  162. data/app/assets/stylesheets/spotlight/_variables.scss +0 -13
  163. data/app/components/blacklight/icons/arrow_alt_circle_left_component.rb +0 -15
  164. data/app/components/blacklight/icons/arrow_alt_circle_right_component.rb +0 -15
  165. data/app/components/spotlight/icon_component.rb +0 -13
  166. data/app/javascript/spotlight/user/browse_group_categories.js +0 -54
  167. data/app/models/concerns/spotlight/resources/web.rb +0 -38
  168. data/app/services/spotlight/iiif_resource_resolver.rb +0 -78
  169. data/app/views/shared/_exhibit_navbar.html.erb +0 -2
  170. data/app/views/shared/_header_navbar.html.erb +0 -6
  171. data/app/views/spotlight/catalog/_admin_index_header_default.html.erb +0 -23
  172. data/app/views/spotlight/catalog/_admin_thumbnail_default.html.erb +0 -7
  173. data/app/views/spotlight/catalog/_document_row.html.erb +0 -2
  174. data/app/views/spotlight/catalog/_index_compact_default.html.erb +0 -21
  175. data/lib/generators/spotlight/templates/javascript/jquery-shim.js +0 -1
  176. data/vendor/assets/javascripts/tiny-slider.js +0 -3221
  177. data/vendor/assets/stylesheets/tiny-slider.css +0 -1
  178. /data/app/assets/stylesheets/spotlight/{_breadcrumbs.scss → _breadcrumbs.css} +0 -0
  179. /data/app/assets/stylesheets/spotlight/{_croppable.scss → _croppable.css} +0 -0
  180. /data/app/assets/stylesheets/spotlight/{_modals.scss → _modals.css} +0 -0
  181. /data/app/assets/stylesheets/spotlight/{_utilities.scss → _utilities.css} +0 -0
@@ -10,7 +10,7 @@ module Spotlight
10
10
  def destroy
11
11
  @lock.destroy
12
12
 
13
- render plain: '', status: :no_content
13
+ head :no_content
14
14
  end
15
15
  end
16
16
  end
@@ -17,8 +17,7 @@ module Spotlight
17
17
  helper_method :get_search_results, :search_results, :fetch, :page_collection_name
18
18
 
19
19
  before_action do
20
- blacklight_config.action_mapping.default = blacklight_config.index
21
- blacklight_config.action_mapping.show = blacklight_config.index
20
+ blacklight_config.action_mapping.show.top_level_config = :index
22
21
  blacklight_config.view.gallery.classes = 'row-cols-2 row-cols-md-4' unless @page&.display_sidebar
23
22
  end
24
23
 
@@ -118,10 +117,11 @@ module Spotlight
118
117
 
119
118
  # Add a Page specific search_results method that takes user params as
120
119
  # an option and passes that off to the search service to get results
121
- # @param [Hash] the query parameters
120
+ # @param [Hash] user_params the query parameters
122
121
  # @return [Object] the search results object from the configured search service
123
122
  def search_results(user_params)
124
- search_service(user_params).search_results
123
+ state = search_state_class.new(user_params, blacklight_config, self)
124
+ search_service_class.new(config: blacklight_config, search_state: state, **search_service_context).search_results
125
125
  end
126
126
 
127
127
  def undo_link
@@ -197,13 +197,13 @@ module Spotlight
197
197
 
198
198
  def redirect_page_to_related_locale_version
199
199
  pages_for_id = current_exhibit.pages.find(params[:id])
200
- if pages_for_id.default_locale_page
201
- redirect_to polymorphic_path([current_exhibit, pages_for_id.default_locale_page])
202
- elsif pages_for_id.translated_page_for(I18n.locale)
203
- redirect_to polymorphic_path([current_exhibit, pages_for_id.translated_page_for(I18n.locale)])
204
- else
205
- raise ActiveRecord::RecordNotFound
206
- end
200
+ default_page = pages_for_id.default_locale_page || pages_for_id
201
+ target = default_page.translated_page_for(I18n.locale) || pages_for_id.default_locale_page
202
+ raise ActiveRecord::RecordNotFound unless target
203
+
204
+ # Pass the locale explicitly. A host app route default (e.g., `locale: nil`) overrides default_url_options.
205
+ locale = target.locale unless target.default_locale?
206
+ redirect_to polymorphic_path([current_exhibit, target], locale:)
207
207
  end
208
208
  end
209
209
  end
@@ -28,7 +28,7 @@ module Spotlight
28
28
  redirect_to spotlight.admin_exhibit_catalog_path(@resource.exhibit, sort: :timestamp)
29
29
  else
30
30
  flash[:error] = @resource.errors.full_messages.to_sentence if @resource.errors.present?
31
- render action: 'new'
31
+ render action: 'new', status: :unprocessable_content
32
32
  end
33
33
  end
34
34
  alias update create
@@ -45,7 +45,7 @@ module Spotlight
45
45
  initial_exception = nil
46
46
 
47
47
  ([self] + additional_locale_routing_scopes).each do |scope|
48
- return scope.public_send(:url_for, params.to_unsafe_h.merge(locale:))
48
+ return scope.url_for(params.to_unsafe_h.merge(locale:))
49
49
  rescue ActionController::UrlGenerationError => e
50
50
  initial_exception ||= e
51
51
  end
@@ -59,9 +59,9 @@ module Spotlight
59
59
 
60
60
  # Can search for named routes directly in the main app, omitting
61
61
  # the "main_app." prefix
62
- def method_missing(method, *args, &)
62
+ def method_missing(method, *, &)
63
63
  if main_app_url_helper?(method)
64
- main_app.send(method, *args)
64
+ main_app.send(method, *)
65
65
  else
66
66
  super
67
67
  end
@@ -93,6 +93,17 @@ module Spotlight
93
93
  end
94
94
  end
95
95
 
96
+ ##
97
+ # Helper to search the exhibit with a saved search's query. Falls back to the
98
+ # default search field so that a search without a query still lands on the
99
+ # results page instead of being redirected to the exhibit home page
100
+ def path_to_saved_search(search)
101
+ spotlight.search_exhibit_catalog_path(
102
+ search.exhibit,
103
+ search.query_params.presence || { search_field: search.blacklight_config.default_search_field.key }
104
+ )
105
+ end
106
+
96
107
  ##
97
108
  # Override Blacklight's #render_document_class to inject a private class
98
109
  def render_document_class(document = @document)
@@ -27,8 +27,8 @@ module Spotlight
27
27
  end
28
28
 
29
29
  # Expecting to upstream this override in https://github.com/projectblacklight/blacklight/pull/3343/files
30
- def document_presenter(document, view_config: nil, **kwargs)
31
- (view_config&.document_presenter_class || document_presenter_class(document)).new(document, self, view_config:, **kwargs)
30
+ def document_presenter(document, view_config: nil, **)
31
+ (view_config&.document_presenter_class || document_presenter_class(document)).new(document, self, view_config:, **)
32
32
  end
33
33
 
34
34
  def document_presenter_class(_document)
@@ -1,31 +1,43 @@
1
1
  export default class {
2
2
  connect() {
3
- $("[data-action='add-another']").on("click", function (event) {
4
- event.preventDefault()
5
-
6
- var templateId = $(this).data("template-id")
7
-
8
- var template = document.querySelector("#" + templateId)
9
- var clone = document.importNode(template.content, true)
10
-
11
- var count =
12
- $(this)
13
- .closest(".form-group")
14
- .find('[name="' + $(clone).find("[name]").attr("name") + '"]')
15
- .length + 1
16
- $(clone)
17
- .find("[id]")
18
- .each(function (index, el) {
19
- $(el).attr("id", $(el).attr("id") + "_" + String(count))
20
- })
3
+ document
4
+ .querySelectorAll("[data-action='add-another']")
5
+ .forEach((button) => {
6
+ button.addEventListener("click", (event) => {
7
+ event.preventDefault()
21
8
 
22
- $(clone)
23
- .find("[for]")
24
- .each(function (index, el) {
25
- $(el).attr("for", $(el).attr("for") + "_" + String(count))
26
- })
9
+ const templateId = button.dataset.templateId
10
+ if (!templateId) return
11
+
12
+ const template = document.getElementById(templateId)
13
+ if (!template) return
14
+
15
+ const clone = document.importNode(template.content, true)
16
+
17
+ const formGroup = button.closest(".form-group")
18
+ if (!formGroup) return
27
19
 
28
- $(clone).insertBefore(this)
29
- })
20
+ const firstNamedElement = clone.querySelector("[name]")
21
+ if (!firstNamedElement) return
22
+
23
+ const nameAttr = firstNamedElement.getAttribute("name")
24
+ const existingElements = formGroup.querySelectorAll(
25
+ `[name="${nameAttr}"]`,
26
+ )
27
+ const count = existingElements.length + 1
28
+
29
+ clone.querySelectorAll("[id]").forEach((el) => {
30
+ const currentId = el.getAttribute("id")
31
+ el.setAttribute("id", `${currentId}_${count}`)
32
+ })
33
+
34
+ clone.querySelectorAll("[for]").forEach((el) => {
35
+ const currentFor = el.getAttribute("for")
36
+ el.setAttribute("for", `${currentFor}_${count}`)
37
+ })
38
+
39
+ button.parentNode.insertBefore(clone, button)
40
+ })
41
+ })
30
42
  }
31
43
  }
@@ -1,40 +1,57 @@
1
1
  import Iiif from "spotlight/admin/iiif"
2
+ import multiImageSelector from "spotlight/admin/multi_image_selector"
2
3
 
3
4
  export function addImageSelector(input, panel, manifestUrl, initialize) {
4
5
  if (!manifestUrl) {
5
6
  showNonIiifAlert(input)
6
7
  return
7
8
  }
8
- var cropper = input.data("iiifCropper")
9
- $.ajax(manifestUrl).done(function (manifest) {
10
- var iiifManifest = new Iiif(manifestUrl, manifest)
11
-
12
- var thumbs = iiifManifest.imagesArray()
13
-
14
- hideNonIiifAlert(input)
15
-
16
- if (initialize) {
17
- cropper.setIiifFields(thumbs[0])
18
- panel.multiImageSelector() // Clears out existing selector
19
- }
20
-
21
- if (thumbs.length > 1) {
22
- panel.show()
23
- panel.multiImageSelector(
24
- thumbs,
25
- function (selectorImage) {
26
- cropper.setIiifFields(selectorImage)
27
- },
28
- cropper.iiifImageField.val(),
29
- )
30
- }
31
- })
9
+ var cropper = input.iiifCropper
10
+ fetch(manifestUrl)
11
+ .then(function (response) {
12
+ return response.json()
13
+ })
14
+ .then(function (manifest) {
15
+ var iiifManifest = new Iiif(manifestUrl, manifest)
16
+
17
+ var thumbs = iiifManifest.imagesArray()
18
+
19
+ hideNonIiifAlert(input)
20
+
21
+ if (initialize) {
22
+ cropper.setIiifFields(thumbs[0])
23
+ multiImageSelector(panel) // Clears out existing selector
24
+ }
25
+
26
+ if (thumbs.length > 1) {
27
+ panel.style.display = ""
28
+ multiImageSelector(
29
+ panel,
30
+ thumbs,
31
+ function (selectorImage) {
32
+ cropper.setIiifFields(selectorImage)
33
+ },
34
+ cropper.iiifImageField.value,
35
+ )
36
+ }
37
+ })
38
+ }
39
+
40
+ function findNonIiifAlert(input) {
41
+ if (!input || !input.parentElement) return null
42
+ var prev = input.parentElement.previousElementSibling
43
+ if (prev && prev.matches('[data-behavior="non-iiif-alert"]')) {
44
+ return prev
45
+ }
46
+ return null
32
47
  }
33
48
 
34
49
  function showNonIiifAlert(input) {
35
- input.parent().prev('[data-behavior="non-iiif-alert"]').show()
50
+ var alert = findNonIiifAlert(input)
51
+ if (alert) alert.style.display = ""
36
52
  }
37
53
 
38
54
  function hideNonIiifAlert(input) {
39
- input.parent().prev('[data-behavior="non-iiif-alert"]').hide()
55
+ var alert = findNonIiifAlert(input)
56
+ if (alert) alert.style.display = "none"
40
57
  }
@@ -1,81 +1,96 @@
1
1
  export default class {
2
2
  connect() {
3
- $("[data-expanded-add-button]").each((_i, el) =>
4
- this.addExpandBehaviorToButton($(el)),
5
- )
3
+ document
4
+ .querySelectorAll("[data-expanded-add-button]")
5
+ .forEach((el) => this.addExpandBehaviorToButton(el))
6
6
  }
7
7
 
8
8
  addExpandBehaviorToButton(button) {
9
9
  var settings = {
10
- speed: button.data("speed") || 450,
11
- animate_width: button.data("animate_width") || 425,
10
+ speed: parseInt(button.dataset.speed || "450", 10),
11
+ animate_width: parseInt(button.dataset.animateWidth || "425", 10),
12
12
  }
13
- var target = $(button.data("field-target"))
14
- var save = $("input[data-behavior='save']", target)
15
- var cancel = $("input[data-behavior='cancel']", target)
16
- var input = $("input[type='text']", target)
17
- var original_width = button.outerWidth()
13
+ var target = document.querySelector(button.dataset.fieldTarget)
14
+ var save = target.querySelector("input[data-behavior='save']")
15
+ var cancel = target.querySelector("input[data-behavior='cancel']")
16
+ var input = target.querySelector("input[type='text']")
17
+ var original_width = button.offsetWidth
18
18
  var expanded = false
19
19
 
20
20
  // Animate button open when the mouse enters or
21
21
  // the button is given focus (i.e. clicked/tabbed)
22
- button.on("mouseenter focus", function () {
23
- expandButton()
24
- })
22
+ button.addEventListener("mouseenter", expandButton)
23
+ button.addEventListener("focus", expandButton)
25
24
 
26
25
  // Don't allow blank titles
27
- save.on("click", function () {
26
+ save.addEventListener("click", function (e) {
28
27
  if (inputEmpty()) {
29
- return false
28
+ e.preventDefault()
29
+ e.stopPropagation()
30
30
  }
31
31
  })
32
32
 
33
33
  // Empty input and collapse
34
34
  // button on cancel click
35
- cancel.on("click", function (e) {
35
+ cancel.addEventListener("click", function (e) {
36
36
  e.preventDefault()
37
- input.val("")
37
+ input.value = ""
38
38
  collapseButton()
39
39
  })
40
40
 
41
41
  // Collapse the button on when
42
42
  // an empty input loses focus
43
- input.on("blur", function () {
43
+ input.addEventListener("blur", function () {
44
44
  if (inputEmpty()) {
45
45
  collapseButton()
46
46
  }
47
47
  })
48
+
48
49
  function expandButton() {
49
50
  // If this has not yet been expanded, recalculate original_width to
50
51
  // handle things that may have been originally hidden.
51
52
  if (!expanded) {
52
- original_width = button.outerWidth()
53
+ original_width = button.offsetWidth
53
54
  }
54
- if (button.outerWidth() <= original_width + 5) {
55
+ if (button.offsetWidth <= original_width + 5) {
55
56
  expanded = true
56
- button.animate(
57
+ var anim = button.animate(
57
58
  { width: settings.animate_width + "px" },
58
- settings.speed,
59
- function () {
60
- target.show(0, function () {
61
- input.focus()
62
- // Set the button to auto width to make
63
- // sure it has room for any inputs
64
- button.width("auto")
65
- // Explicitly set the width of the button
66
- // so the close animation works properly
67
- button.width(button.width())
68
- })
69
- },
59
+ { duration: settings.speed },
70
60
  )
61
+ anim.onfinish = function () {
62
+ button.style.width = settings.animate_width + "px"
63
+ showElement(target)
64
+ input.focus()
65
+ // Set the button to auto width to make
66
+ // sure it has room for any inputs
67
+ button.style.width = "auto"
68
+ // Explicitly set the width of the button
69
+ // so the close animation works properly
70
+ button.style.width = button.offsetWidth + "px"
71
+ }
71
72
  }
72
73
  }
73
74
  function collapseButton() {
74
- target.hide()
75
- button.animate({ width: original_width + "px" }, settings.speed)
75
+ target.style.display = "none"
76
+ var anim = button.animate(
77
+ { width: original_width + "px" },
78
+ { duration: settings.speed },
79
+ )
80
+ anim.onfinish = function () {
81
+ button.style.width = original_width + "px"
82
+ }
83
+ }
84
+ // Show an element that may be hidden via a CSS class by overriding with an
85
+ // appropriate inline display value (mirrors jQuery's .show()).
86
+ function showElement(el) {
87
+ el.style.display = ""
88
+ if (window.getComputedStyle(el).display === "none") {
89
+ el.style.display = "inline-block"
90
+ }
76
91
  }
77
92
  function inputEmpty() {
78
- return $.trim(input.val()) == ""
93
+ return input.value.trim() == ""
79
94
  }
80
95
  }
81
96
  }
@@ -7,70 +7,92 @@ export default class {
7
7
 
8
8
  // Add Select/Deselect all behavior for metadata field names for a given view e.g. Item details.
9
9
  addCheckboxToggleBehavior() {
10
- $("[data-behavior='metadata-select']").each(function () {
11
- var selectCheckbox = $(this)
12
- var parentCell = selectCheckbox.parents("th")
13
- var table = parentCell.closest("table")
14
- var columnRows = $(
15
- "tr td:nth-child(" + (parentCell.index() + 1) + ")",
16
- table,
17
- )
18
- var checkboxes = $("input[type='checkbox']", columnRows)
19
- updateSelectAllInput(selectCheckbox, columnRows)
20
- // Add the check/uncheck behavior to the select/deselect all checkbox
21
- selectCheckbox.on("click", function () {
22
- var allChecked = allCheckboxesChecked(columnRows)
23
- columnRows.each(function () {
24
- $("input[type='checkbox']", $(this)).prop("checked", !allChecked)
25
- })
26
- })
27
- // When a single checkbox is selected/unselected, the "All" checkbox should be updated accordingly.
28
- checkboxes.each(function () {
29
- $(this).on("change", function () {
30
- updateSelectAllInput(selectCheckbox, columnRows)
31
- })
32
- })
33
- })
34
-
35
10
  // Check number of checkboxes against the number of checked
36
11
  // checkboxes to determine if all of them are checked or not
37
- function allCheckboxesChecked(elements) {
38
- return (
39
- $("input[type='checkbox']", elements).length ==
40
- $("input[type='checkbox']:checked", elements).length
41
- )
12
+ function allCheckboxesChecked(cells) {
13
+ let total = 0
14
+ let checked = 0
15
+ cells.forEach((cell) => {
16
+ cell.querySelectorAll("input[type='checkbox']").forEach((cb) => {
17
+ total++
18
+ if (cb.checked) {
19
+ checked++
20
+ }
21
+ })
22
+ })
23
+ return total === checked
42
24
  }
43
25
 
44
26
  // Check or uncheck the "All" checkbox for each view column, e.g. Item details, List, etc.
45
- function updateSelectAllInput(checkbox, elements) {
46
- if (allCheckboxesChecked(elements)) {
47
- checkbox.prop("checked", true)
48
- } else {
49
- checkbox.prop("checked", false)
50
- }
27
+ function updateSelectAllInput(checkbox, cells) {
28
+ checkbox.checked = allCheckboxesChecked(cells)
51
29
  }
30
+
31
+ document
32
+ .querySelectorAll("[data-behavior='metadata-select']")
33
+ .forEach((selectCheckbox) => {
34
+ const parentCell = selectCheckbox.closest("th")
35
+ if (!parentCell) return
36
+
37
+ const table = parentCell.closest("table")
38
+ if (!table) return
39
+
40
+ const columnIndex = Array.from(parentCell.parentNode.children).indexOf(
41
+ parentCell,
42
+ )
43
+ const columnRows = table.querySelectorAll(
44
+ `tr td:nth-child(${columnIndex + 1})`,
45
+ )
46
+
47
+ const checkboxes = []
48
+ columnRows.forEach((cell) => {
49
+ cell.querySelectorAll("input[type='checkbox']").forEach((cb) => {
50
+ checkboxes.push(cb)
51
+ })
52
+ })
53
+
54
+ updateSelectAllInput(selectCheckbox, columnRows)
55
+
56
+ // Add the check/uncheck behavior to the select/deselect all checkbox
57
+ selectCheckbox.addEventListener("click", () => {
58
+ const allChecked = allCheckboxesChecked(columnRows)
59
+ columnRows.forEach((cell) => {
60
+ cell.querySelectorAll("input[type='checkbox']").forEach((cb) => {
61
+ cb.checked = !allChecked
62
+ cb.dispatchEvent(new Event("change", { bubbles: true }))
63
+ })
64
+ })
65
+ updateSelectAllInput(selectCheckbox, columnRows)
66
+ })
67
+
68
+ // When a single checkbox is selected/unselected, the "All" checkbox should be updated accordingly.
69
+ checkboxes.forEach((cb) => {
70
+ cb.addEventListener("change", () => {
71
+ updateSelectAllInput(selectCheckbox, columnRows)
72
+ })
73
+ })
74
+ })
52
75
  }
53
76
 
54
77
  addEnableToggleBehavior() {
55
- $("[data-behavior='enable-feature']").each(function () {
56
- var checkbox = $(this)
57
- var target = $($(this).data("target"))
78
+ document
79
+ .querySelectorAll("[data-behavior='enable-feature']")
80
+ .forEach((checkbox) => {
81
+ const targetSelector = checkbox.dataset.target
82
+ if (!targetSelector) return
83
+ const target = document.querySelector(targetSelector)
84
+ if (!target) return
58
85
 
59
- checkbox.on("change", function () {
60
- if ($(this).is(":checked")) {
61
- target
62
- .find("input:checkbox")
63
- .not("[data-behavior='enable-feature']")
64
- .prop("checked", true)
65
- .attr("disabled", false)
66
- } else {
67
- target
68
- .find("input:checkbox")
69
- .not("[data-behavior='enable-feature']")
70
- .prop("checked", false)
71
- .attr("disabled", true)
72
- }
86
+ checkbox.addEventListener("change", () => {
87
+ const isChecked = checkbox.checked
88
+ target.querySelectorAll("input[type='checkbox']").forEach((cb) => {
89
+ if (!cb.matches("[data-behavior='enable-feature']")) {
90
+ cb.checked = isChecked
91
+ cb.disabled = !isChecked
92
+ cb.dispatchEvent(new Event("change", { bubbles: true }))
93
+ }
94
+ })
95
+ })
73
96
  })
74
- })
75
97
  }
76
98
  }