blacklight-spotlight 5.3.2 → 6.0.0.rc2

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 (211) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +41 -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/custom_field_form_group_component.rb +40 -0
  26. data/app/components/spotlight/document_admin_table_component.html.erb +2 -2
  27. data/app/components/spotlight/edit_sidecar_component.html.erb +18 -0
  28. data/app/components/spotlight/edit_sidecar_component.rb +41 -0
  29. data/app/components/spotlight/masthead_component.html.erb +18 -0
  30. data/app/components/spotlight/masthead_component.rb +46 -0
  31. data/app/components/spotlight/save_search_component.html.erb +1 -1
  32. data/app/components/spotlight/sidecar_form_field_component.html.erb +18 -0
  33. data/app/components/spotlight/sidecar_form_field_component.rb +71 -0
  34. data/app/components/spotlight/solr_document_legacy_embed_component.html.erb +0 -4
  35. data/app/components/spotlight/solr_document_legacy_embed_component.rb +2 -2
  36. data/app/components/spotlight/tag_selector_component.html.erb +1 -1
  37. data/app/components/spotlight/tag_selector_component.rb +3 -2
  38. data/app/components/spotlight/upload_field_form_group_component.rb +33 -0
  39. data/app/controllers/concerns/spotlight/controller.rb +15 -14
  40. data/app/controllers/concerns/spotlight/search_helper.rb +2 -5
  41. data/app/controllers/spotlight/browse_controller.rb +1 -6
  42. data/app/controllers/spotlight/catalog_controller.rb +2 -3
  43. data/app/controllers/spotlight/concerns/application_controller.rb +4 -6
  44. data/app/controllers/spotlight/exhibits_controller.rb +22 -10
  45. data/app/controllers/spotlight/lock_controller.rb +1 -1
  46. data/app/controllers/spotlight/pages_controller.rb +11 -11
  47. data/app/controllers/spotlight/resources/upload_controller.rb +1 -1
  48. data/app/controllers/spotlight/resources_controller.rb +1 -1
  49. data/app/controllers/spotlight/solr_controller.rb +5 -1
  50. data/app/helpers/spotlight/application_helper.rb +14 -26
  51. data/app/helpers/spotlight/crud_link_helpers.rb +0 -12
  52. data/app/helpers/spotlight/main_app_helpers.rb +2 -2
  53. data/app/javascript/spotlight/admin/add_another.js +37 -25
  54. data/app/javascript/spotlight/admin/add_image_selector.js +43 -26
  55. data/app/javascript/spotlight/admin/add_new_button.js +51 -36
  56. data/app/javascript/spotlight/admin/blacklight_configuration.js +76 -54
  57. data/app/javascript/spotlight/admin/block_mixins/autocompleteable.js +102 -101
  58. data/app/javascript/spotlight/admin/block_mixins/formable.js +91 -75
  59. data/app/javascript/spotlight/admin/block_mixins/plustextable.js +46 -48
  60. data/app/javascript/spotlight/admin/blocks/block.js +27 -28
  61. data/app/javascript/spotlight/admin/blocks/browse_block.js +14 -10
  62. data/app/javascript/spotlight/admin/blocks/browse_group_categories_block.js +14 -10
  63. data/app/javascript/spotlight/admin/blocks/pages_block.js +5 -4
  64. data/app/javascript/spotlight/admin/blocks/resources_block.js +61 -41
  65. data/app/javascript/spotlight/admin/blocks/search_result_block.js +24 -7
  66. data/app/javascript/spotlight/admin/blocks/solr_documents_base_block.js +103 -50
  67. data/app/javascript/spotlight/admin/blocks/solr_documents_carousel_block.js +50 -26
  68. data/app/javascript/spotlight/admin/blocks/solr_documents_features_block.js +47 -23
  69. data/app/javascript/spotlight/admin/blocks/uploaded_items_block.js +35 -19
  70. data/app/javascript/spotlight/admin/crop.js +146 -66
  71. data/app/javascript/spotlight/admin/croppable.js +5 -4
  72. data/app/javascript/spotlight/admin/croppable_modal.js +67 -32
  73. data/app/javascript/spotlight/admin/edit_in_place.js +69 -54
  74. data/app/javascript/spotlight/admin/exhibits.js +92 -45
  75. data/app/javascript/spotlight/admin/form_observer.js +92 -78
  76. data/app/javascript/spotlight/admin/multi_image_selector.js +201 -153
  77. data/app/javascript/spotlight/admin/pages.js +13 -7
  78. data/app/javascript/spotlight/admin/progress_monitor.js +65 -50
  79. data/app/javascript/spotlight/admin/readonly_checkbox.js +7 -3
  80. data/app/javascript/spotlight/admin/search_typeahead.js +20 -11
  81. data/app/javascript/spotlight/admin/select_related_input.js +23 -23
  82. data/app/javascript/spotlight/admin/serialize_json.js +120 -0
  83. data/app/javascript/spotlight/admin/sir-trevor/block_controls.js +24 -11
  84. data/app/javascript/spotlight/admin/sir-trevor/block_limits.js +9 -6
  85. data/app/javascript/spotlight/admin/sir-trevor/locales.js +2 -2
  86. data/app/javascript/spotlight/admin/spotlight_nestable.js +2 -5
  87. data/app/javascript/spotlight/admin/translation_progress.js +18 -13
  88. data/app/javascript/spotlight/admin/users.js +151 -64
  89. data/app/javascript/spotlight/user/carousel.js +104 -32
  90. data/app/javascript/spotlight/user/clear_form_button.js +24 -14
  91. data/app/javascript/spotlight/user/index.js +0 -2
  92. data/app/javascript/spotlight/user/zpr_links.js +99 -40
  93. data/app/jobs/concerns/spotlight/gather_documents.rb +1 -1
  94. data/app/jobs/spotlight/add_uploads_from_csv.rb +31 -8
  95. data/app/jobs/spotlight/cleanup_job_trackers_job.rb +5 -3
  96. data/app/models/concerns/spotlight/access_controls_enforcement_search_builder.rb +13 -2
  97. data/app/models/concerns/spotlight/browse_category_search_builder.rb +3 -3
  98. data/app/models/concerns/spotlight/exhibit_documents.rb +2 -2
  99. data/app/models/concerns/spotlight/sitemap.rb +2 -2
  100. data/app/models/concerns/spotlight/solr_document/finder.rb +2 -2
  101. data/app/models/concerns/spotlight/solr_document.rb +1 -47
  102. data/app/models/sir_trevor_rails/blocks/browse_block.rb +0 -4
  103. data/app/models/sir_trevor_rails/blocks/solr_documents_block.rb +2 -1
  104. data/app/models/spotlight/blacklight_configuration.rb +5 -3
  105. data/app/models/spotlight/contact_email.rb +2 -2
  106. data/app/models/spotlight/custom_field.rb +17 -0
  107. data/app/models/spotlight/exhibit.rb +28 -0
  108. data/app/models/spotlight/featured_image.rb +1 -1
  109. data/app/models/spotlight/field_metadata.rb +10 -5
  110. data/app/models/spotlight/job_tracker.rb +0 -18
  111. data/app/models/spotlight/main_navigation.rb +2 -2
  112. data/app/models/spotlight/page.rb +3 -3
  113. data/app/models/spotlight/resources/iiif_harvester.rb +7 -4
  114. data/app/models/spotlight/resources/iiif_manifest.rb +0 -4
  115. data/app/models/spotlight/resources/iiif_manifest_metadata.rb +1 -3
  116. data/app/models/spotlight/resources/iiif_service.rb +21 -6
  117. data/app/models/spotlight/resources/upload.rb +6 -0
  118. data/app/models/spotlight/search.rb +5 -9
  119. data/app/models/spotlight/solr_document_sidecar.rb +18 -0
  120. data/app/services/spotlight/bulk_updates_csv_template_service.rb +1 -1
  121. data/app/services/spotlight/etl/pipeline.rb +2 -2
  122. data/app/services/spotlight/etl/step.rb +2 -2
  123. data/app/views/catalog/_remove_tags.html.erb +2 -2
  124. data/app/views/layouts/spotlight/base.html.erb +3 -6
  125. data/app/views/layouts/spotlight/spotlight.html.erb +2 -2
  126. data/app/views/shared/_analytics.html.erb +4 -3
  127. data/app/views/shared/_masthead.html.erb +2 -18
  128. data/app/views/spotlight/about_pages/_empty.html.erb +1 -1
  129. data/app/views/spotlight/about_pages/_sidebar.html.erb +10 -8
  130. data/app/views/spotlight/browse/_search.html.erb +2 -2
  131. data/app/views/spotlight/browse/_search_box.html.erb +6 -14
  132. data/app/views/spotlight/browse/index.html.erb +1 -1
  133. data/app/views/spotlight/browse/show.html.erb +1 -1
  134. data/app/views/spotlight/catalog/_document_admin_table.html.erb +1 -1
  135. data/app/views/spotlight/catalog/_edit_default.html.erb +1 -1
  136. data/app/views/spotlight/catalog/edit.html.erb +1 -1
  137. data/app/views/spotlight/dashboards/_page.html.erb +1 -1
  138. data/app/views/spotlight/exhibits/_exhibit_card.html.erb +3 -1
  139. data/app/views/spotlight/exhibits/_export.html.erb +17 -1
  140. data/app/views/spotlight/exhibits/_form.html.erb +20 -4
  141. data/app/views/spotlight/exhibits/_missing_exhibits.html.erb +3 -3
  142. data/app/views/spotlight/exhibits/index.html.erb +21 -8
  143. data/app/views/spotlight/feature_pages/_empty.html.erb +1 -1
  144. data/app/views/spotlight/feature_pages/_sidebar.html.erb +17 -15
  145. data/app/views/spotlight/home_pages/_empty.html.erb +7 -7
  146. data/app/views/spotlight/pages/show.html.erb +1 -0
  147. data/app/views/spotlight/resources/upload/_form.html.erb +2 -2
  148. data/app/views/spotlight/sir_trevor/blocks/_browse_group_categories_block.html.erb +5 -16
  149. data/app/views/spotlight/sir_trevor/blocks/_embedded_document.html.erb +3 -5
  150. data/app/views/spotlight/sir_trevor/blocks/_link_to_search_block.html.erb +1 -1
  151. data/app/views/spotlight/sir_trevor/blocks/_solr_documents_carousel_block.html.erb +11 -2
  152. data/app/views/spotlight/sites/_exhibit.html.erb +1 -1
  153. data/config/i18n-tasks.yml +1 -1
  154. data/config/locales/spotlight.ar.yml +1 -2
  155. data/config/locales/spotlight.de.yml +1 -2
  156. data/config/locales/spotlight.en.yml +39 -10
  157. data/config/locales/spotlight.es.yml +1 -2
  158. data/config/locales/spotlight.fr.yml +1 -2
  159. data/config/locales/spotlight.it.yml +1 -2
  160. data/config/locales/spotlight.ja.yml +39 -0
  161. data/config/locales/spotlight.zh.yml +1 -2
  162. data/db/migrate/20261007133748_add_discovery_enabled_to_spotlight_exhibits.rb +5 -0
  163. data/lib/generators/spotlight/assets/importmap_generator.rb +2 -10
  164. data/lib/generators/spotlight/assets/propshaft_generator.rb +5 -4
  165. data/lib/generators/spotlight/install_generator.rb +2 -4
  166. data/lib/generators/spotlight/templates/catalog_controller.rb +0 -1
  167. data/lib/generators/spotlight/templates/config/initializers/spotlight_initializer.rb +26 -4
  168. data/lib/generators/spotlight/templates/solr/conf/schema.xml +4 -3
  169. data/lib/generators/spotlight/templates/solr/conf/solrconfig.xml +3 -8
  170. data/lib/migration/page_language.rb +0 -2
  171. data/lib/spotlight/engine.rb +28 -9
  172. data/lib/spotlight/search_state.rb +7 -11
  173. data/lib/spotlight/upload_field_config.rb +19 -1
  174. data/lib/spotlight/version.rb +1 -1
  175. data/lib/spotlight.rb +1 -1
  176. data/spec/support/features/capybara_wait_metadata_helper.rb +3 -1
  177. data/spec/support/features/test_features_helpers.rb +24 -1
  178. data/spec/support/iiif_manifest_fixtures.rb +33 -0
  179. data/spec/support/stub_dns_resolution.rb +12 -0
  180. metadata +50 -80
  181. data/app/assets/stylesheets/spotlight/_uploaded_items_block.scss +0 -7
  182. data/app/assets/stylesheets/spotlight/_variables.scss +0 -13
  183. data/app/components/blacklight/icons/arrow_alt_circle_left_component.rb +0 -15
  184. data/app/components/blacklight/icons/arrow_alt_circle_right_component.rb +0 -15
  185. data/app/components/blacklight/icons/info_component.rb +0 -15
  186. data/app/components/blacklight/icons/zoom_in_component.rb +0 -15
  187. data/app/components/blacklight/icons/zoom_out_component.rb +0 -15
  188. data/app/components/spotlight/icon_component.rb +0 -13
  189. data/app/javascript/spotlight/user/browse_group_categories.js +0 -54
  190. data/app/mailers/spotlight/invitation_mailer.rb +0 -21
  191. data/app/models/concerns/spotlight/resources/web.rb +0 -38
  192. data/app/services/spotlight/iiif_resource_resolver.rb +0 -78
  193. data/app/views/catalog/_image_default.html.erb +0 -6
  194. data/app/views/shared/_exhibit_navbar.html.erb +0 -2
  195. data/app/views/shared/_header_navbar.html.erb +0 -6
  196. data/app/views/spotlight/catalog/_admin_index_header_default.html.erb +0 -23
  197. data/app/views/spotlight/catalog/_admin_thumbnail_default.html.erb +0 -7
  198. data/app/views/spotlight/catalog/_curation_mode_toggle_default.html.erb +0 -1
  199. data/app/views/spotlight/catalog/_document_row.html.erb +0 -2
  200. data/app/views/spotlight/catalog/_edit_sidecar.html.erb +0 -24
  201. data/app/views/spotlight/catalog/_index_compact_default.html.erb +0 -21
  202. data/app/views/spotlight/custom_fields/form_group/_text.html.erb +0 -23
  203. data/app/views/spotlight/custom_fields/form_group/_vocab.html.erb +0 -23
  204. data/app/views/spotlight/invitation_mailer/exhibit_invitation_notification.html.erb +0 -12
  205. data/lib/generators/spotlight/templates/javascript/jquery-shim.js +0 -1
  206. data/vendor/assets/javascripts/tiny-slider.js +0 -3221
  207. data/vendor/assets/stylesheets/tiny-slider.css +0 -1
  208. /data/app/assets/stylesheets/spotlight/{_breadcrumbs.scss → _breadcrumbs.css} +0 -0
  209. /data/app/assets/stylesheets/spotlight/{_croppable.scss → _croppable.css} +0 -0
  210. /data/app/assets/stylesheets/spotlight/{_modals.scss → _modals.css} +0 -0
  211. /data/app/assets/stylesheets/spotlight/{_utilities.scss → _utilities.css} +0 -0
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spotlight
4
+ # Renders an upload field (Spotlight::UploadFieldConfig) on the catalog edit and upload forms through its configured component
5
+ class UploadFieldFormGroupComponent < ViewComponent::Base
6
+ attr_reader :form, :config, :value, :inline
7
+
8
+ def initialize(form:, config:, value: nil, inline: false)
9
+ @form = form
10
+ @config = config
11
+ @value = value
12
+ @inline = inline
13
+ super()
14
+ end
15
+
16
+ def call
17
+ render config.component.new(
18
+ form:,
19
+ id: config.field_name,
20
+ label:,
21
+ value:,
22
+ field_type: config.form_field_type,
23
+ multiple: config.is_multiple?,
24
+ inline:
25
+ )
26
+ end
27
+
28
+ def label
29
+ solr_field = Array(config.solr_field || config.field_name).first.to_s
30
+ helpers.blacklight_config.index_fields[solr_field]&.label || config.label || solr_field
31
+ end
32
+ end
33
+ end
@@ -13,12 +13,21 @@ module Spotlight
13
13
  included do
14
14
  helper_method :current_site, :current_exhibit, :current_masthead, :exhibit_masthead?, :resource_masthead?, :breadcrumbs
15
15
  before_action :set_exhibit_locale_scope, :set_locale
16
+ after_action :add_previewable_exhibit_robots_header
17
+ # If your app overrides search_state_class, subclass Spotlight::SearchState (rather than
18
+ # Blacklight::SearchState) to keep exhibit-scoped document routing.
19
+ self.search_state_class = Spotlight::SearchState
16
20
  end
17
21
 
18
22
  def set_exhibit_locale_scope
19
23
  Translation.current_exhibit = current_exhibit
20
24
  end
21
25
 
26
+ # Previewable exhibits are only meant to be reachable by link, so ask search engines not to index them
27
+ def add_previewable_exhibit_robots_header
28
+ response.headers['X-Robots-Tag'] = 'noindex' if current_exhibit&.previewable?
29
+ end
30
+
22
31
  def current_site
23
32
  @current_site ||= Spotlight::Site.instance
24
33
  end
@@ -77,27 +86,19 @@ module Spotlight
77
86
  end
78
87
  end
79
88
 
80
- def search_state
81
- if current_exhibit
82
- @search_state ||= Spotlight::SearchState.new(super, current_exhibit)
83
- else
84
- super
85
- end
86
- end
87
-
88
- def search_action_url(*args, **kwargs)
89
+ def search_action_url(*, **)
89
90
  if current_exhibit
90
- exhibit_search_action_url(*args, **kwargs)
91
+ exhibit_search_action_url(*, **)
91
92
  else
92
- main_app.search_catalog_url(*args, **kwargs)
93
+ main_app.search_catalog_url(*, **)
93
94
  end
94
95
  end
95
96
 
96
- def search_facet_path(*args, **kwargs)
97
+ def search_facet_path(*, **)
97
98
  if current_exhibit
98
- exhibit_search_facet_path(*args, **kwargs)
99
+ exhibit_search_facet_path(*, **)
99
100
  else
100
- main_app.facet_catalog_url(*args, **kwargs)
101
+ main_app.facet_catalog_url(*, **)
101
102
  end
102
103
  end
103
104
 
@@ -3,11 +3,8 @@
3
3
  module Spotlight
4
4
  # ...
5
5
  module SearchHelper
6
- def search_service(user_params = respond_to?(:search_state, true) ? search_state.to_h : {})
7
- klass = respond_to?(:search_service_class) ? search_service_class : Blacklight::SearchService
8
-
9
- klass.new(config: blacklight_config, user_params:, **search_service_context)
10
- end
6
+ extend ActiveSupport::Concern
7
+ include Blacklight::Searchable
11
8
 
12
9
  # @return [Hash] a hash of context information to pass through to the search service
13
10
  def search_service_context
@@ -22,8 +22,7 @@ module Spotlight
22
22
  before_action do
23
23
  blacklight_config.track_search_session.storage = false
24
24
  blacklight_config.view.gallery.classes = 'row-cols-2 row-cols-md-4' if blacklight_config.view.key? :gallery
25
- blacklight_config.action_mapping.default = blacklight_config.index
26
- blacklight_config.action_mapping.show = blacklight_config.index
25
+ blacklight_config.action_mapping.show.top_level_config = :index
27
26
  end
28
27
 
29
28
  def index
@@ -121,10 +120,6 @@ module Spotlight
121
120
  Spotlight::Engine.config.default_browse_index_view_type
122
121
  end
123
122
 
124
- def render_save_this_search?
125
- false
126
- end
127
-
128
123
  def render_curator_actions?
129
124
  false
130
125
  end
@@ -35,7 +35,6 @@ module Spotlight
35
35
  blacklight_config.view.select! { |k, _v| k == :admin_table }
36
36
  unless blacklight_config.view.key? :admin_table
37
37
  blacklight_config.view.admin_table(document_component: Spotlight::DocumentAdminTableComponent,
38
- partials: [:index_compact],
39
38
  document_actions: [])
40
39
  end
41
40
 
@@ -66,7 +65,7 @@ module Spotlight
66
65
  # results when a partial match is passed in the "q" parameter.
67
66
  def autocomplete
68
67
  @response = search_service.search_results do |builder|
69
- builder.with(builder.blacklight_params.merge(search_field: Spotlight::Engine.config.autocomplete_search_field, public: true, rows: 100))
68
+ builder.with(search_state.params.merge(search_field: Spotlight::Engine.config.autocomplete_search_field, public: true, rows: 100))
70
69
  end
71
70
 
72
71
  respond_to do |format|
@@ -200,7 +199,7 @@ module Spotlight
200
199
 
201
200
  def uploaded_resource_params
202
201
  if @document.uploaded_resource?
203
- [{ configured_fields: Spotlight::Resources::Upload.fields(current_exhibit).map(&:field_name) }]
202
+ [{ configured_fields: Spotlight::Resources::Upload.as_strong_params(current_exhibit) }]
204
203
  else
205
204
  []
206
205
  end
@@ -29,8 +29,8 @@ module Spotlight
29
29
  end
30
30
  end
31
31
 
32
- def enabled_in_spotlight_view_type_configuration?(config, *args)
33
- if config.respond_to?(:original) && !blacklight_configuration_context.evaluate_if_unless_configuration(config.original, *args)
32
+ def enabled_in_spotlight_view_type_configuration?(config, *)
33
+ if config.respond_to?(:original) && !blacklight_configuration_context.evaluate_if_unless_configuration(config.original, *)
34
34
  false
35
35
  elsif current_exhibit.nil? || is_a?(Spotlight::PagesController)
36
36
  true
@@ -39,10 +39,8 @@ module Spotlight
39
39
  end
40
40
  end
41
41
 
42
- def field_enabled?(field, *args)
43
- if !field.enabled
44
- false
45
- elsif field.respond_to?(:original) && !blacklight_configuration_context.evaluate_if_unless_configuration(field.original, *args)
42
+ def field_enabled?(field, *)
43
+ if !field.enabled || (field.respond_to?(:original) && !blacklight_configuration_context.evaluate_if_unless_configuration(field.original, *))
46
44
  false
47
45
  elsif field.is_a?(Blacklight::Configuration::SortField) || field.is_a?(Blacklight::Configuration::SearchField)
48
46
  field.enabled
@@ -8,17 +8,16 @@ module Spotlight
8
8
 
9
9
  before_action :authenticate_user!, except: [:index]
10
10
  before_action :set_tab, only: %i[edit update]
11
+ before_action :load_exhibits, only: [:index]
11
12
 
12
13
  load_and_authorize_resource
13
14
 
14
15
  def index
15
- @published_exhibits = @exhibits.includes(:thumbnail).published.ordered_by_weight.page(params[:page])
16
- @published_exhibits = @published_exhibits.tagged_with(params[:tag]) if params[:tag]
17
- if @exhibits.one?
18
- redirect_to @exhibits.first, flash: flash.to_h
19
- else
20
- render layout: 'spotlight/home'
21
- end
16
+ return redirect_to @exhibits.first, flash: flash.to_h if @exhibits.one?
17
+
18
+ @published_exhibits = @exhibits.includes(:thumbnail).discoverable.ordered_by_weight.page(params[:page])
19
+ @published_exhibits = @published_exhibits.tagged_with(params[:tag]) if params[:tag].present?
20
+ render layout: 'spotlight/home'
22
21
  end
23
22
 
24
23
  def show
@@ -86,18 +85,18 @@ module Spotlight
86
85
  redirect_to main_app.root_url, notice: t(:'helpers.submit.exhibit.destroyed', model: @exhibit.class.model_name.human.downcase)
87
86
  end
88
87
 
89
- protected
90
-
91
88
  def current_exhibit
92
89
  @exhibit if @exhibit&.persisted?
93
90
  end
94
91
 
92
+ protected
93
+
95
94
  def exhibit_params
96
95
  params.require(:exhibit).permit(
97
96
  :title,
98
97
  :subtitle,
99
98
  :description,
100
- :published,
99
+ :publishing_status,
101
100
  :tag_list,
102
101
  tag_list: [],
103
102
  contact_emails_attributes: %i[id email],
@@ -105,6 +104,19 @@ module Spotlight
105
104
  )
106
105
  end
107
106
 
107
+ # Runs before load_and_authorize_resource to set @exhibits from discoverable
108
+ # exhibits, not just exhibits that can be accessed.
109
+ def load_exhibits
110
+ exhibits = Spotlight::Exhibit.accessible_by(current_ability)
111
+ return @exhibits = exhibits.discoverable unless current_user
112
+
113
+ @exhibits = if can?(:manage, Spotlight::Exhibit)
114
+ exhibits
115
+ else
116
+ exhibits.discoverable.or(exhibits.where(id: current_user.exhibits.select(:id)))
117
+ end
118
+ end
119
+
108
120
  def set_tab
109
121
  @tab = params[:tab]
110
122
  end
@@ -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
@@ -48,7 +48,7 @@ module Spotlight
48
48
  end
49
49
 
50
50
  def data_param_keys
51
- Spotlight::Resources::Upload.fields(current_exhibit).map(&:field_name) +
51
+ Spotlight::Resources::Upload.as_strong_params(current_exhibit) +
52
52
  current_exhibit.custom_fields.as_strong_params
53
53
  end
54
54
  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
@@ -50,7 +50,7 @@ module Spotlight
50
50
 
51
51
  create_or_update_solr_document_sidecar(doc, r)
52
52
 
53
- doc.to_solr.merge(@exhibit.solr_data).merge(other_field_data)
53
+ doc.to_solr.stringify_keys.merge(@exhibit.solr_data.stringify_keys).merge(other_field_data)
54
54
  end
55
55
  end
56
56
 
@@ -69,6 +69,10 @@ module Spotlight
69
69
  end
70
70
 
71
71
  def create_or_update_solr_document_sidecar(doc, data)
72
+ # The sidecar already records the unique key as its document_id. (The payload is a raw
73
+ # Solr document, so here "id" is always the unique key; in other sidecar data it may be
74
+ # the slug of an "ID" custom field.)
75
+ data = data.except(doc.class.unique_key.to_s)
72
76
  return if data.blank?
73
77
 
74
78
  sidecar = doc.sidecar(@exhibit)
@@ -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)
@@ -125,13 +136,6 @@ module Spotlight
125
136
  selected_view || default_document_index_view_type
126
137
  end
127
138
 
128
- # Return the list of views that are configured to display for a block
129
- def selected_search_block_views(block)
130
- block.as_json[:data].select do |_key, value|
131
- value == 'on'
132
- end.keys.map(&:to_s)
133
- end
134
-
135
139
  # Create checkbox for selecting/deselecting metadata fields for a given view in metadata configuration
136
140
  def select_deselect_action(id)
137
141
  check_box_tag(
@@ -143,26 +147,10 @@ module Spotlight
143
147
  )
144
148
  end
145
149
 
146
- def uploaded_field_label(config)
147
- solr_field = Array(config.solr_field || config.field_name).first.to_s
148
- blacklight_config.index_fields[solr_field]&.label || config.label || t(".#{solr_field}")
149
- end
150
-
151
150
  def available_view_fields
152
151
  current_exhibit.blacklight_configuration.default_blacklight_config.view.to_h.reject { |_k, v| v.if == false }
153
152
  end
154
153
 
155
- def render_search_bar
156
- return super if defined?(super)
157
-
158
- render((blacklight_config&.view_config(document_index_view_type)&.search_bar_component || Blacklight::SearchBarComponent).new(
159
- url: search_action_url,
160
- advanced_search_url: search_action_url(action: 'advanced_search'),
161
- params: search_state.params_for_search.except(:qt),
162
- autocomplete_path: suggest_index_catalog_path
163
- ))
164
- end
165
-
166
154
  def render_constraints(localized_params = nil, local_search_state = nil)
167
155
  return super if defined?(super)
168
156
 
@@ -20,24 +20,12 @@ module Spotlight
20
20
  link_to action_default_value(model, :view), link, link_to_options
21
21
  end
22
22
 
23
- def create_link(model, *args)
24
- link_to_options = args.extract_options!
25
- link = args.first || polymorphic_path([spotlight, model], action: :new)
26
- link_to action_default_value(model), link, link_to_options
27
- end
28
-
29
23
  def exhibit_create_link(model, *args)
30
24
  link_to_options = args.extract_options!
31
25
  link = args.first || polymorphic_path([spotlight, current_exhibit, model], action: :new)
32
26
  link_to action_default_value(model), link, link_to_options
33
27
  end
34
28
 
35
- def edit_link(model, *args)
36
- link_to_options = args.extract_options!
37
- link = args.first || polymorphic_path([spotlight, model], action: :edit)
38
- link_to action_default_value(model), link, link_to_options
39
- end
40
-
41
29
  def exhibit_edit_link(model, *args)
42
30
  link_to_options = args.extract_options!
43
31
  link = args.first || polymorphic_path([spotlight, model.exhibit, model], action: :edit)
@@ -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
  }