blacklight 7.43.1 → 8.0.0.beta1

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 (432) hide show
  1. checksums.yaml +4 -4
  2. data/.env +2 -3
  3. data/.github/workflows/ruby.yml +81 -0
  4. data/.rubocop.yml +244 -15
  5. data/.rubocop_todo.yml +137 -429
  6. data/.solr_wrapper.yml +1 -3
  7. data/Gemfile +11 -6
  8. data/README.md +11 -3
  9. data/VERSION +1 -1
  10. data/app/assets/javascripts/blacklight/blacklight.esm.js +162 -374
  11. data/app/assets/javascripts/blacklight/blacklight.esm.js.map +1 -1
  12. data/app/assets/javascripts/blacklight/blacklight.js +374 -488
  13. data/app/assets/javascripts/blacklight/blacklight.js.map +1 -1
  14. data/app/assets/stylesheets/blacklight/_autocomplete.scss +25 -0
  15. data/app/assets/stylesheets/blacklight/_blacklight_base.scss +1 -1
  16. data/app/assets/stylesheets/blacklight/_bookmark.scss +16 -0
  17. data/app/assets/stylesheets/blacklight/_bootstrap_overrides.scss +8 -0
  18. data/app/assets/stylesheets/blacklight/_constraints.scss +4 -4
  19. data/app/assets/stylesheets/blacklight/_facets.scss +72 -44
  20. data/app/assets/stylesheets/blacklight/_header.scss +0 -15
  21. data/app/assets/stylesheets/blacklight/_icons.scss +0 -14
  22. data/app/assets/stylesheets/blacklight/_mixins.scss +20 -0
  23. data/app/assets/stylesheets/blacklight/_modal.scss +8 -2
  24. data/app/assets/stylesheets/blacklight/_search_form.scss +30 -3
  25. data/app/assets/stylesheets/blacklight/_search_history.scss +10 -1
  26. data/app/assets/stylesheets/blacklight/_search_results.scss +6 -2
  27. data/app/assets/stylesheets/blacklight/blacklight_defaults.scss +4 -1
  28. data/app/builders/blacklight/action_builder.rb +18 -9
  29. data/app/components/blacklight/advanced_search_form_component.html.erb +3 -3
  30. data/app/components/blacklight/advanced_search_form_component.rb +8 -10
  31. data/app/components/blacklight/constraints_component.rb +27 -37
  32. data/app/components/blacklight/document/action_component.rb +12 -10
  33. data/app/components/blacklight/document/actions_component.rb +2 -2
  34. data/app/components/blacklight/document/bookmark_component.html.erb +9 -0
  35. data/app/components/blacklight/document/bookmark_component.rb +4 -2
  36. data/app/components/blacklight/document/citation_component.rb +5 -3
  37. data/app/components/blacklight/document/group_component.rb +7 -3
  38. data/app/components/blacklight/document/sidebar_component.html.erb +2 -0
  39. data/app/components/blacklight/document/sidebar_component.rb +16 -0
  40. data/app/components/blacklight/document/thumbnail_component.html.erb +2 -7
  41. data/app/components/blacklight/document/thumbnail_component.rb +1 -9
  42. data/app/components/blacklight/document_component.html.erb +1 -1
  43. data/app/components/blacklight/document_component.rb +16 -78
  44. data/app/components/blacklight/document_metadata_component.html.erb +2 -4
  45. data/app/components/blacklight/document_metadata_component.rb +5 -10
  46. data/app/components/blacklight/facet_component.rb +3 -3
  47. data/app/components/blacklight/facet_field_checkboxes_component.html.erb +4 -4
  48. data/app/components/blacklight/facet_field_checkboxes_component.rb +1 -1
  49. data/app/components/blacklight/facet_field_component.html.erb +4 -5
  50. data/app/components/blacklight/facet_field_component.rb +9 -2
  51. data/app/components/blacklight/facet_field_list_component.html.erb +3 -3
  52. data/app/components/blacklight/facet_field_list_component.rb +37 -5
  53. data/app/components/blacklight/facet_field_no_layout_component.rb +0 -2
  54. data/app/components/blacklight/facet_item_component.rb +1 -43
  55. data/app/components/blacklight/facet_item_pivot_component.rb +21 -23
  56. data/app/components/blacklight/header_component.rb +1 -1
  57. data/app/components/blacklight/hidden_search_state_component.rb +1 -2
  58. data/app/components/blacklight/icons/icon_component.rb +4 -9
  59. data/app/components/blacklight/icons/legacy_icon_component.rb +30 -0
  60. data/app/components/blacklight/icons/list_component.rb +16 -0
  61. data/app/components/blacklight/icons/search_component.rb +16 -0
  62. data/app/components/blacklight/metadata_field_component.html.erb +2 -2
  63. data/app/components/blacklight/metadata_field_component.rb +24 -8
  64. data/app/components/blacklight/metadata_field_layout_component.rb +4 -25
  65. data/app/components/blacklight/response/facet_group_component.html.erb +3 -5
  66. data/app/components/blacklight/response/facet_group_component.rb +29 -8
  67. data/app/components/blacklight/response/pagination_component.html.erb +1 -1
  68. data/app/components/blacklight/response/pagination_component.rb +2 -11
  69. data/app/components/blacklight/response/sort_component.html.erb +6 -1
  70. data/app/components/blacklight/response/sort_component.rb +1 -16
  71. data/app/components/blacklight/response/spellcheck_component.rb +18 -7
  72. data/app/components/blacklight/response/view_type_button_component.rb +3 -7
  73. data/app/components/blacklight/response/view_type_component.rb +4 -6
  74. data/app/components/blacklight/search/sidebar_component.html.erb +8 -0
  75. data/app/components/blacklight/search/sidebar_component.rb +17 -0
  76. data/app/components/blacklight/search_bar_component.html.erb +20 -15
  77. data/app/components/blacklight/search_bar_component.rb +2 -16
  78. data/app/components/blacklight/search_button_component.rb +3 -3
  79. data/app/components/blacklight/search_context_component.rb +43 -10
  80. data/app/components/blacklight/search_header_component.html.erb +2 -0
  81. data/app/components/blacklight/search_header_component.rb +6 -0
  82. data/app/components/blacklight/start_over_button_component.rb +5 -3
  83. data/app/components/blacklight/system/dropdown_component.rb +8 -5
  84. data/app/components/blacklight/system/flash_message_component.html.erb +4 -2
  85. data/app/components/blacklight/system/flash_message_component.rb +12 -3
  86. data/app/components/blacklight/system/modal_component.html.erb +1 -1
  87. data/app/components/blacklight/system/modal_component.rb +1 -3
  88. data/app/components/blacklight/top_navbar_component.html.erb +1 -1
  89. data/app/components/blacklight/top_navbar_component.rb +0 -4
  90. data/app/controllers/bookmarks_controller.rb +1 -0
  91. data/app/controllers/catalog_controller.rb +1 -0
  92. data/app/controllers/concerns/blacklight/bookmarks.rb +10 -9
  93. data/app/controllers/concerns/blacklight/catalog.rb +21 -83
  94. data/app/controllers/concerns/blacklight/controller.rb +3 -41
  95. data/app/controllers/concerns/blacklight/search_context.rb +25 -7
  96. data/app/controllers/concerns/blacklight/search_history.rb +2 -0
  97. data/app/controllers/concerns/blacklight/searchable.rb +12 -1
  98. data/app/controllers/concerns/blacklight/token_based_user.rb +13 -1
  99. data/app/controllers/search_history_controller.rb +1 -0
  100. data/app/helpers/blacklight/blacklight_helper_behavior.rb +12 -310
  101. data/app/helpers/blacklight/catalog_helper_behavior.rb +22 -139
  102. data/app/helpers/blacklight/component_helper_behavior.rb +2 -53
  103. data/app/helpers/blacklight/configuration_helper_behavior.rb +2 -119
  104. data/app/helpers/blacklight/facets_helper_behavior.rb +4 -321
  105. data/app/helpers/blacklight/icon_helper_behavior.rb +5 -7
  106. data/app/helpers/blacklight/layout_helper_behavior.rb +4 -3
  107. data/app/helpers/blacklight/render_partials_helper_behavior.rb +11 -31
  108. data/app/helpers/blacklight/url_helper_behavior.rb +12 -97
  109. data/app/helpers/blacklight_helper.rb +1 -0
  110. data/app/helpers/catalog_helper.rb +1 -0
  111. data/app/javascript/blacklight/bookmark_toggle.js +13 -19
  112. data/app/javascript/blacklight/button_focus.js +12 -10
  113. data/app/javascript/blacklight/checkbox_submit.js +68 -123
  114. data/app/javascript/blacklight/core.js +5 -7
  115. data/app/javascript/blacklight/index.js +13 -0
  116. data/app/javascript/blacklight/modal.js +99 -164
  117. data/app/javascript/blacklight/modalForm.js +60 -0
  118. data/app/javascript/blacklight/search_context.js +46 -54
  119. data/app/models/blacklight/facet_paginator.rb +3 -2
  120. data/app/models/blacklight/icon.rb +4 -2
  121. data/app/models/bookmark.rb +0 -2
  122. data/app/models/concerns/blacklight/configurable.rb +5 -4
  123. data/app/models/concerns/blacklight/document/active_model_shim.rb +1 -10
  124. data/app/models/concerns/blacklight/document/cache_key.rb +1 -0
  125. data/app/models/concerns/blacklight/document/dublin_core.rb +2 -1
  126. data/app/models/concerns/blacklight/document/email.rb +1 -0
  127. data/app/models/concerns/blacklight/document/export.rb +2 -1
  128. data/app/models/concerns/blacklight/document/extensions.rb +1 -0
  129. data/app/models/concerns/blacklight/document/schema_org.rb +1 -0
  130. data/app/models/concerns/blacklight/document/semantic_fields.rb +2 -1
  131. data/app/models/concerns/blacklight/document/sms.rb +1 -0
  132. data/app/models/concerns/blacklight/suggest/response.rb +1 -0
  133. data/app/models/concerns/blacklight/user.rb +17 -8
  134. data/app/models/record_mailer.rb +13 -12
  135. data/app/models/search.rb +1 -7
  136. data/app/models/solr_document.rb +1 -0
  137. data/app/presenters/blacklight/clause_presenter.rb +1 -1
  138. data/app/presenters/blacklight/document_presenter.rb +23 -50
  139. data/app/presenters/blacklight/facet_field_presenter.rb +39 -14
  140. data/app/presenters/blacklight/facet_grouped_item_presenter.rb +1 -5
  141. data/app/presenters/blacklight/facet_item_pivot_presenter.rb +60 -0
  142. data/app/presenters/blacklight/facet_item_presenter.rb +3 -9
  143. data/app/presenters/blacklight/field_presenter.rb +1 -0
  144. data/app/presenters/blacklight/index_presenter.rb +2 -40
  145. data/app/presenters/blacklight/json_presenter.rb +10 -6
  146. data/app/presenters/blacklight/rendering/link_to_facet.rb +2 -5
  147. data/app/presenters/blacklight/show_presenter.rb +1 -9
  148. data/app/presenters/blacklight/thumbnail_presenter.rb +1 -1
  149. data/app/services/blacklight/bookmarks_search_builder.rb +22 -0
  150. data/app/services/blacklight/field_retriever.rb +12 -21
  151. data/app/services/blacklight/search_service.rb +10 -17
  152. data/app/values/blacklight/types.rb +0 -18
  153. data/app/views/bookmarks/_clear_bookmarks_widget.html.erb +8 -1
  154. data/app/views/bookmarks/_tools.html.erb +7 -12
  155. data/app/views/catalog/_advanced_search_form.html.erb +0 -1
  156. data/app/views/catalog/_bookmark_control.html.erb +1 -1
  157. data/app/views/catalog/_citation.html.erb +1 -1
  158. data/app/views/catalog/_constraints.html.erb +1 -14
  159. data/app/views/catalog/_document.atom.builder +12 -14
  160. data/app/views/catalog/_document.html.erb +5 -3
  161. data/app/views/catalog/_document.rss.builder +2 -4
  162. data/app/views/catalog/_facet_layout.html.erb +2 -2
  163. data/app/views/catalog/_facets.html.erb +5 -4
  164. data/app/views/catalog/_home_text.html.erb +2 -14
  165. data/app/views/catalog/_per_page_widget.html.erb +10 -1
  166. data/app/views/catalog/_search_form.html.erb +2 -2
  167. data/app/views/catalog/_search_header.html.erb +1 -2
  168. data/app/views/catalog/_search_results.html.erb +2 -2
  169. data/app/views/catalog/_search_sidebar.html.erb +5 -1
  170. data/app/views/catalog/_show_main_content.html.erb +11 -16
  171. data/app/views/catalog/_show_sidebar.html.erb +2 -2
  172. data/app/views/catalog/_show_tools.html.erb +8 -14
  173. data/app/views/catalog/_view_type_group.html.erb +1 -1
  174. data/app/views/catalog/email.html.erb +2 -2
  175. data/app/views/catalog/email_success.html.erb +5 -6
  176. data/app/views/catalog/facet.html.erb +7 -5
  177. data/app/views/catalog/index.atom.builder +12 -14
  178. data/app/views/catalog/index.html.erb +4 -1
  179. data/app/views/catalog/index.json.jbuilder +19 -19
  180. data/app/views/catalog/index.rss.builder +1 -1
  181. data/app/views/catalog/opensearch.xml.builder +1 -1
  182. data/app/views/catalog/sms.html.erb +2 -2
  183. data/app/views/catalog/sms_success.html.erb +5 -6
  184. data/app/views/catalog/suggest.html.erb +3 -0
  185. data/app/views/kaminari/blacklight/_page.html.erb +2 -1
  186. data/app/views/layouts/blacklight/base.html.erb +13 -2
  187. data/app/views/search_history/index.html.erb +6 -2
  188. data/app/views/shared/_flash_messages.html.erb +1 -1
  189. data/app/views/shared/_modal.html.erb +3 -3
  190. data/blacklight.gemspec +7 -13
  191. data/config/importmap.rb +1 -1
  192. data/config/locales/blacklight.ar.yml +0 -1
  193. data/config/locales/blacklight.ca.yml +0 -1
  194. data/config/locales/blacklight.de.yml +0 -1
  195. data/config/locales/blacklight.en.yml +0 -2
  196. data/config/locales/blacklight.es.yml +0 -1
  197. data/config/locales/blacklight.fr.yml +0 -1
  198. data/config/locales/blacklight.hu.yml +0 -1
  199. data/config/locales/blacklight.it.yml +0 -1
  200. data/config/locales/blacklight.nl.yml +0 -1
  201. data/config/locales/blacklight.pt-BR.yml +0 -1
  202. data/config/locales/blacklight.sq.yml +0 -1
  203. data/config/locales/blacklight.zh.yml +0 -1
  204. data/config/routes.rb +3 -2
  205. data/db/migrate/20140202020201_create_searches.rb +1 -0
  206. data/db/migrate/20140202020202_create_bookmarks.rb +1 -0
  207. data/db/migrate/20140320000000_add_polymorphic_type_to_bookmarks.rb +1 -0
  208. data/docker-compose.yml +3 -3
  209. data/lib/blacklight/abstract_repository.rb +1 -8
  210. data/lib/blacklight/component.rb +47 -10
  211. data/lib/blacklight/configuration/context.rb +4 -4
  212. data/lib/blacklight/configuration/display_field.rb +7 -9
  213. data/lib/blacklight/configuration/facet_field.rb +17 -11
  214. data/lib/blacklight/configuration/field.rb +7 -6
  215. data/lib/blacklight/configuration/fields.rb +12 -15
  216. data/lib/blacklight/configuration/index_field.rb +1 -0
  217. data/lib/blacklight/configuration/null_display_field.rb +17 -0
  218. data/lib/blacklight/configuration/search_field.rb +1 -0
  219. data/lib/blacklight/configuration/show_field.rb +1 -0
  220. data/lib/blacklight/configuration/sort_field.rb +3 -2
  221. data/lib/blacklight/configuration/tool_config.rb +1 -0
  222. data/lib/blacklight/configuration/view_config.rb +14 -10
  223. data/lib/blacklight/configuration.rb +310 -365
  224. data/lib/blacklight/engine.rb +8 -38
  225. data/lib/blacklight/exceptions.rb +2 -2
  226. data/lib/blacklight/nested_open_struct_with_hash_access.rb +7 -13
  227. data/lib/blacklight/open_struct_with_hash_access.rb +23 -6
  228. data/lib/blacklight/parameters.rb +7 -21
  229. data/lib/blacklight/routes/exportable.rb +1 -0
  230. data/lib/blacklight/routes/searchable.rb +2 -1
  231. data/lib/blacklight/routes.rb +1 -0
  232. data/lib/blacklight/runtime_registry.rb +0 -24
  233. data/lib/blacklight/search_builder.rb +10 -10
  234. data/lib/blacklight/search_state/filter_field.rb +8 -25
  235. data/lib/blacklight/search_state/pivot_filter_field.rb +144 -0
  236. data/lib/blacklight/search_state.rb +23 -79
  237. data/lib/blacklight/solr/document.rb +1 -0
  238. data/lib/blacklight/solr/facet_paginator.rb +1 -0
  239. data/lib/blacklight/solr/repository.rb +14 -39
  240. data/lib/blacklight/solr/request.rb +1 -0
  241. data/lib/blacklight/solr/response/facets.rb +21 -5
  242. data/lib/blacklight/solr/response/group.rb +1 -0
  243. data/lib/blacklight/solr/response/group_response.rb +1 -0
  244. data/lib/blacklight/solr/response/more_like_this.rb +1 -0
  245. data/lib/blacklight/solr/response/pagination_methods.rb +4 -3
  246. data/lib/blacklight/solr/response/params.rb +5 -4
  247. data/lib/blacklight/solr/response/response.rb +1 -0
  248. data/lib/blacklight/solr/response/spelling.rb +1 -0
  249. data/lib/blacklight/solr/response.rb +16 -3
  250. data/lib/blacklight/solr/search_builder_behavior.rb +16 -35
  251. data/lib/blacklight/solr.rb +7 -0
  252. data/lib/blacklight/version.rb +1 -0
  253. data/lib/blacklight.rb +26 -14
  254. data/lib/generators/blacklight/assets/importmap_generator.rb +8 -9
  255. data/lib/generators/blacklight/assets/propshaft_generator.rb +2 -11
  256. data/lib/generators/blacklight/assets/sprockets_generator.rb +17 -51
  257. data/lib/generators/blacklight/assets_generator.rb +11 -7
  258. data/lib/generators/blacklight/controller_generator.rb +4 -3
  259. data/lib/generators/blacklight/document_generator.rb +1 -0
  260. data/lib/generators/blacklight/install_generator.rb +3 -5
  261. data/lib/generators/blacklight/models_generator.rb +1 -0
  262. data/lib/generators/blacklight/search_builder_generator.rb +1 -0
  263. data/lib/generators/blacklight/solr_generator.rb +1 -1
  264. data/lib/generators/blacklight/templates/catalog_controller.rb +34 -8
  265. data/lib/generators/blacklight/templates/solr/conf/solrconfig.xml +6 -71
  266. data/lib/generators/blacklight/test_support_generator.rb +5 -3
  267. data/lib/generators/blacklight/user_generator.rb +7 -9
  268. data/lib/railties/blacklight.rake +6 -7
  269. data/package.json +10 -13
  270. data/rollup.config.js +27 -0
  271. data/spec/components/blacklight/constraints_component_spec.rb +17 -13
  272. data/spec/components/blacklight/document/action_component_spec.rb +6 -1
  273. data/spec/components/blacklight/document_component_spec.rb +22 -131
  274. data/spec/components/blacklight/facet_component_spec.rb +3 -18
  275. data/spec/components/blacklight/facet_field_checkboxes_component_spec.rb +1 -2
  276. data/spec/components/blacklight/facet_field_list_component_spec.rb +7 -6
  277. data/spec/components/blacklight/facet_item_pivot_component_spec.rb +10 -9
  278. data/spec/components/blacklight/response/view_type_component_spec.rb +66 -0
  279. data/spec/components/blacklight/search_bar_component_spec.rb +1 -1
  280. data/spec/components/blacklight/search_context_component_spec.rb +17 -8
  281. data/spec/controllers/application_controller_spec.rb +0 -23
  282. data/spec/controllers/blacklight/catalog/component_configuration_spec.rb +1 -6
  283. data/spec/controllers/blacklight/{base_spec.rb → catalog_spec.rb} +2 -2
  284. data/spec/controllers/bookmarks_controller_spec.rb +2 -3
  285. data/spec/controllers/catalog_controller_spec.rb +13 -135
  286. data/spec/features/advanced_search_spec.rb +0 -56
  287. data/spec/features/autocomplete_spec.rb +1 -1
  288. data/spec/features/axe_spec.rb +1 -6
  289. data/spec/features/bookmarks_spec.rb +1 -1
  290. data/spec/features/facets_spec.rb +6 -4
  291. data/spec/features/search_context_spec.rb +5 -11
  292. data/spec/features/search_results_spec.rb +0 -33
  293. data/spec/features/sitelinks_search_box.rb +13 -0
  294. data/spec/helpers/blacklight/configuration_helper_behavior_spec.rb +2 -138
  295. data/spec/helpers/blacklight/facets_helper_behavior_spec.rb +0 -386
  296. data/spec/helpers/blacklight/icon_helper_behavior_spec.rb +8 -0
  297. data/spec/helpers/blacklight/layout_helper_behavior_spec.rb +3 -20
  298. data/spec/helpers/blacklight/render_partials_helper_behavior_spec.rb +5 -7
  299. data/spec/helpers/blacklight/url_helper_behavior_spec.rb +9 -131
  300. data/spec/helpers/blacklight_helper_spec.rb +8 -252
  301. data/spec/helpers/catalog_helper_spec.rb +7 -118
  302. data/spec/i18n_spec.rb +1 -0
  303. data/spec/integration/generators/blacklight/solr_generator_spec.rb +1 -1
  304. data/spec/lib/blacklight/component_spec.rb +27 -32
  305. data/spec/lib/blacklight/configuration/facet_field_spec.rb +27 -16
  306. data/spec/lib/blacklight/configuration/field_spec.rb +1 -1
  307. data/spec/lib/blacklight/configuration/view_config_spec.rb +1 -1
  308. data/spec/lib/blacklight/open_struct_with_hash_access_spec.rb +2 -2
  309. data/spec/lib/blacklight/parameters_spec.rb +1 -4
  310. data/spec/lib/blacklight/search_state/filter_field_spec.rb +4 -4
  311. data/spec/lib/blacklight/search_state/pivot_filter_field_spec.rb +117 -0
  312. data/spec/lib/blacklight/search_state_spec.rb +80 -198
  313. data/spec/lib/tasks/blacklight_task_spec.rb +1 -0
  314. data/spec/models/blacklight/configuration_spec.rb +17 -51
  315. data/spec/models/blacklight/document/active_model_shim_spec.rb +2 -2
  316. data/spec/models/blacklight/document/dublin_core_spec.rb +2 -2
  317. data/spec/models/blacklight/icon_spec.rb +31 -15
  318. data/spec/models/blacklight/search_builder_spec.rb +9 -9
  319. data/spec/models/blacklight/solr/document_spec.rb +3 -3
  320. data/spec/models/blacklight/solr/repository_spec.rb +0 -114
  321. data/spec/models/blacklight/solr/response/facets_spec.rb +27 -27
  322. data/spec/models/blacklight/solr/response/group_response_spec.rb +1 -0
  323. data/spec/models/blacklight/solr/response/group_spec.rb +1 -0
  324. data/spec/models/blacklight/solr/response_spec.rb +9 -2
  325. data/spec/models/blacklight/solr/search_builder_spec.rb +24 -44
  326. data/spec/models/blacklight/user_spec.rb +22 -0
  327. data/spec/models/solr_document_spec.rb +3 -9
  328. data/spec/presenters/blacklight/clause_presenter_spec.rb +1 -0
  329. data/spec/presenters/blacklight/document_presenter_spec.rb +2 -3
  330. data/spec/presenters/blacklight/facet_field_presenter_spec.rb +85 -12
  331. data/spec/presenters/blacklight/facet_grouped_item_presenter_spec.rb +1 -0
  332. data/spec/presenters/blacklight/facet_item_presenter_spec.rb +14 -13
  333. data/spec/presenters/blacklight/field_presenter_spec.rb +0 -14
  334. data/spec/presenters/blacklight/index_presenter_spec.rb +2 -5
  335. data/spec/presenters/blacklight/json_presenter_spec.rb +1 -0
  336. data/spec/presenters/blacklight/link_alternate_presenter_spec.rb +3 -2
  337. data/spec/presenters/blacklight/show_presenter_spec.rb +20 -30
  338. data/spec/presenters/thumbnail_presenter_spec.rb +1 -1
  339. data/spec/requests/load_suggestions_spec.rb +16 -0
  340. data/spec/routing/catalog_routing_spec.rb +2 -1
  341. data/spec/services/blacklight/search_service_spec.rb +39 -76
  342. data/spec/spec_helper.rb +8 -9
  343. data/spec/support/controller_level_helpers.rb +1 -2
  344. data/spec/support/features/search_helpers.rb +39 -0
  345. data/spec/support/features/session_helpers.rb +1 -0
  346. data/spec/support/features.rb +3 -0
  347. data/spec/support/view_component_capybara_test_helpers.rb +8 -0
  348. data/spec/test_app_templates/Gemfile.extra +1 -0
  349. data/spec/test_app_templates/lib/generators/test_app_generator.rb +8 -1
  350. data/spec/views/catalog/_document.html.erb_spec.rb +3 -34
  351. data/spec/views/catalog/_facet_index_navigation.html.erb_spec.rb +1 -1
  352. data/spec/views/catalog/_paginate_compact.html.erb_spec.rb +0 -2
  353. data/spec/views/catalog/_search_header.erb_spec.rb +1 -0
  354. data/spec/views/catalog/_show_sidebar.erb_spec.rb +1 -0
  355. data/spec/views/catalog/_show_tools.html.erb_spec.rb +5 -66
  356. data/spec/views/catalog/_view_type_group.html.erb_spec.rb +17 -9
  357. data/spec/views/catalog/email_success.html.erb_spec.rb +2 -2
  358. data/spec/views/catalog/facet.html.erb_spec.rb +6 -3
  359. data/spec/views/catalog/index.atom.builder_spec.rb +17 -11
  360. data/spec/views/catalog/index.html.erb_spec.rb +5 -6
  361. data/spec/views/catalog/index.json.jbuilder_spec.rb +2 -2
  362. data/spec/views/catalog/show.html.erb_spec.rb +3 -25
  363. data/spec/views/catalog/sms_success.html.erb_spec.rb +2 -2
  364. data/tasks/blacklight.rake +11 -9
  365. data/template.demo.rb +7 -7
  366. metadata +68 -219
  367. data/.babelrc +0 -11
  368. data/.github/matrix.json +0 -71
  369. data/.github/workflows/build.yml +0 -16
  370. data/.github/workflows/lint.yml +0 -23
  371. data/.github/workflows/main.yml +0 -23
  372. data/.github/workflows/test.yml +0 -52
  373. data/app/assets/images/blacklight/list.svg +0 -1
  374. data/app/assets/images/blacklight/search.svg +0 -1
  375. data/app/assets/stylesheets/blacklight/_twitter_typeahead.scss +0 -37
  376. data/app/components/blacklight/content_areas_shim.rb +0 -13
  377. data/app/components/blacklight/search/per_page_component.html.erb +0 -2
  378. data/app/components/blacklight/search/per_page_component.rb +0 -50
  379. data/app/components/blacklight/search_context/server_item_pagination_component.html.erb +0 -10
  380. data/app/components/blacklight/search_context/server_item_pagination_component.rb +0 -15
  381. data/app/components/blacklight/system/dropdown_button_component.rb +0 -18
  382. data/app/controllers/concerns/blacklight/base.rb +0 -12
  383. data/app/controllers/concerns/blacklight/default_component_configuration.rb +0 -64
  384. data/app/controllers/concerns/blacklight/facet.rb +0 -69
  385. data/app/controllers/concerns/blacklight/search_fields.rb +0 -46
  386. data/app/helpers/blacklight/hash_as_hidden_fields_helper_behavior.rb +0 -27
  387. data/app/helpers/blacklight/render_constraints_helper_behavior.rb +0 -188
  388. data/app/helpers/blacklight/search_history_constraints_helper_behavior.rb +0 -97
  389. data/app/helpers/blacklight/suggest_helper_behavior.rb +0 -13
  390. data/app/javascript/blacklight/autocomplete.js +0 -36
  391. data/app/javascript/blacklight/facet_load.js +0 -22
  392. data/app/presenters/blacklight/search_bar_presenter.rb +0 -47
  393. data/app/views/catalog/_constraints_element.html.erb +0 -14
  394. data/app/views/catalog/_document_action.html.erb +0 -5
  395. data/app/views/catalog/_facet_group.html.erb +0 -5
  396. data/app/views/catalog/_facet_limit.html.erb +0 -3
  397. data/app/views/catalog/_index.html.erb +0 -1
  398. data/app/views/catalog/_index_header.html.erb +0 -22
  399. data/app/views/catalog/_previous_next_doc.html.erb +0 -2
  400. data/app/views/catalog/_show.html.erb +0 -6
  401. data/app/views/catalog/_show_header.html.erb +0 -2
  402. data/app/views/catalog/_thumbnail.html.erb +0 -1
  403. data/lib/blacklight/controller_runtime.rb +0 -42
  404. data/lib/blacklight/deprecations/engine_configuration.rb +0 -66
  405. data/lib/blacklight/deprecations/search_state_normalization.rb +0 -52
  406. data/lib/blacklight/log_subscriber.rb +0 -25
  407. data/spec/components/blacklight/header_component_spec.rb +0 -20
  408. data/spec/components/blacklight/icons/icon_component_spec.rb +0 -42
  409. data/spec/components/blacklight/response/pagination_component_spec.rb +0 -53
  410. data/spec/components/blacklight/search_context/server_item_pagination_component_spec.rb +0 -35
  411. data/spec/controllers/blacklight/facet_spec.rb +0 -33
  412. data/spec/controllers/blacklight/search_fields_spec.rb +0 -62
  413. data/spec/features/citation_spec.rb +0 -10
  414. data/spec/features/sitelinks_search_box_spec.rb +0 -13
  415. data/spec/features/sms_spec.rb +0 -12
  416. data/spec/helpers/blacklight/hash_as_hidden_fields_behavior_spec.rb +0 -26
  417. data/spec/helpers/blacklight/render_constraints_helper_behavior_spec.rb +0 -92
  418. data/spec/helpers/blacklight/search_history_constraints_helper_behavior_spec.rb +0 -101
  419. data/spec/helpers/blacklight/suggest_helper_behavior_spec.rb +0 -48
  420. data/spec/lib/blacklight/engine_spec.rb +0 -41
  421. data/spec/lib/blacklight/runtime_registry_spec.rb +0 -46
  422. data/spec/presenters/blacklight/search_bar_presenter_spec.rb +0 -94
  423. data/spec/services/blacklight/field_retriever_spec.rb +0 -17
  424. data/spec/support/view_component_test_helpers.rb +0 -35
  425. data/spec/views/catalog/_constraints.html.erb_spec.rb +0 -33
  426. data/spec/views/catalog/_facet_group.html.erb_spec.rb +0 -84
  427. data/spec/views/catalog/_facets.html.erb_spec.rb +0 -15
  428. data/spec/views/catalog/_index.html.erb_spec.rb +0 -62
  429. data/spec/views/catalog/_index_header.html.erb_spec.rb +0 -35
  430. data/spec/views/catalog/_previous_next_doc.html.erb_spec.rb +0 -22
  431. data/spec/views/catalog/_show.html.erb_spec.rb +0 -62
  432. data/spec/views/catalog/_thumbnail.html.erb_spec.rb +0 -38
@@ -1,3 +1,56 @@
1
+ const Blacklight = function() {
2
+ const buffer = new Array;
3
+ return {
4
+ onLoad: function(func) {
5
+ buffer.push(func);
6
+ },
7
+
8
+ activate: function() {
9
+ for(let i = 0; i < buffer.length; i++) {
10
+ buffer[i].call();
11
+ }
12
+ },
13
+
14
+ listeners: function () {
15
+ const listeners = [];
16
+ if (typeof Turbo !== 'undefined') {
17
+ listeners.push('turbo:load', 'turbo:frame-load');
18
+ } else if (typeof Turbolinks !== 'undefined' && Turbolinks.supported) {
19
+ // Turbolinks 5
20
+ if (Turbolinks.BrowserAdapter) {
21
+ listeners.push('turbolinks:load');
22
+ } else {
23
+ // Turbolinks < 5
24
+ listeners.push('page:load', 'DOMContentLoaded');
25
+ }
26
+ } else {
27
+ listeners.push('DOMContentLoaded');
28
+ }
29
+
30
+ return listeners;
31
+ }
32
+ };
33
+ }();
34
+
35
+ // turbolinks triggers page:load events on page transition
36
+ // If app isn't using turbolinks, this event will never be triggered, no prob.
37
+ Blacklight.listeners().forEach(function(listener) {
38
+ document.addEventListener(listener, function() {
39
+ Blacklight.activate();
40
+ });
41
+ });
42
+
43
+ Blacklight.onLoad(function () {
44
+ const elem = document.querySelector('.no-js');
45
+
46
+ // The "no-js" class may already have been removed because this function is
47
+ // run on every turbo:load event, in that case, it won't find an element.
48
+ if (!elem) return;
49
+
50
+ elem.classList.remove('no-js');
51
+ elem.classList.add('js');
52
+ });
53
+
1
54
  /* Converts a "toggle" form, with single submit button to add/remove
2
55
  something, like used for Bookmarks, into an AJAXy checkbox instead.
3
56
  Apply to a form. Does require certain assumption about the form:
@@ -10,7 +63,7 @@
10
63
  attribute (HTML5-style doc-*) that contains the id/primary key
11
64
  of the object in question -- used by plugin for a unique value for
12
65
  DOM id's.
13
- Uses HTML for a checkbox compatible with Bootstrap.
66
+ Uses HTML for a checkbox compatible with Bootstrap 4.
14
67
  new CheckboxSubmit(document.querySelector('form.something')).render()
15
68
  */
16
69
  class CheckboxSubmit {
@@ -18,11 +71,11 @@ class CheckboxSubmit {
18
71
  this.form = form;
19
72
  }
20
73
 
21
- clicked(evt) {
74
+ async clicked(evt) {
22
75
  this.spanTarget.innerHTML = this.form.getAttribute('data-inprogress');
23
76
  this.labelTarget.setAttribute('disabled', 'disabled');
24
77
  this.checkboxTarget.setAttribute('disabled', 'disabled');
25
- fetch(this.formTarget.getAttribute('action'), {
78
+ const response = await fetch(this.formTarget.getAttribute('action'), {
26
79
  body: new FormData(this.formTarget),
27
80
  method: this.formTarget.getAttribute('method').toUpperCase(),
28
81
  headers: {
@@ -30,25 +83,16 @@ class CheckboxSubmit {
30
83
  'X-Requested-With': 'XMLHttpRequest',
31
84
  'X-CSRF-Token': document.querySelector('meta[name=csrf-token]')?.content
32
85
  }
33
- }).then((response) => {
34
- if (response.ok) return response.json();
35
- return Promise.reject('response was not ok')
36
- }).then((json) => {
37
- this.labelTarget.removeAttribute('disabled');
38
- this.checkboxTarget.removeAttribute('disabled');
39
- // For accessibility return keyboard focus
40
- // back to the checkbox after form submission
41
- this.checkboxTarget.focus();
42
- this.updateStateFor(!this.checked);
43
- this.bookmarksCounter().forEach(counter => {
44
- counter.innerHTML = json.bookmarks.count;
45
- });
46
-
47
- var e = new CustomEvent('bookmark.blacklight', { detail: { checked: this.checked }, bubbles: true });
48
- this.formTarget.dispatchEvent(e);
49
- }).catch((error) => {
50
- this.handleError(error);
51
86
  });
87
+ this.labelTarget.removeAttribute('disabled');
88
+ this.checkboxTarget.removeAttribute('disabled');
89
+ if (response.ok) {
90
+ const json = await response.json();
91
+ this.updateStateFor(!this.checked);
92
+ document.querySelector('[data-role=bookmark-counter]').innerHTML = json.bookmarks.count;
93
+ } else {
94
+ alert('Error');
95
+ }
52
96
  }
53
97
 
54
98
  get checked() {
@@ -71,17 +115,8 @@ class CheckboxSubmit {
71
115
  return this.form.querySelector('[data-checkboxsubmit-target="span"]')
72
116
  }
73
117
 
74
- bookmarksCounter() {
75
- return document.querySelectorAll('[data-role="bookmark-counter"]')
76
- }
77
-
78
- handleError() {
79
- alert("Unable to save the bookmark at this time.");
80
- }
81
-
82
118
  updateStateFor(state) {
83
- if (state) { this.checkboxTarget.setAttribute('checked', state); }
84
- else { this.checkboxTarget.removeAttribute('checked'); }
119
+ this.checkboxTarget.checked = state;
85
120
 
86
121
  if (state) {
87
122
  this.labelTarget.classList.add('checked');
@@ -97,221 +132,32 @@ class CheckboxSubmit {
97
132
  }
98
133
  }
99
134
 
100
- const BookmarkToggle = (e) => {
101
- const elementType = e.target.getAttribute('data-checkboxsubmit-target');
102
- if (elementType == 'checkbox' || elementType == 'label') {
103
- const form = e.target.closest('form');
104
- if (form) new CheckboxSubmit(form).clicked(e);
105
- if (e.code == 'Space') e.preventDefault();
106
- }
107
- };
108
-
109
- document.addEventListener('click', BookmarkToggle);
110
- document.addEventListener('keydown', function (e) {
111
- if (e.key === 'Enter' || e.code == 'Space') { BookmarkToggle(e); } }
112
- );
113
-
114
- const ButtonFocus = (e) => {
115
- // Button clicks should change focus. As of 10/3/19, Firefox for Mac and
116
- // Safari both do not set focus to a button on button click.
117
- // See https://zellwk.com/blog/inconsistent-button-behavior/ for background information
118
- if (e.target.matches('[data-bs-toggle="collapse"]')) {
119
- e.target.focus();
120
- }
121
- };
122
-
123
- document.addEventListener('click', ButtonFocus);
124
-
125
- const Core = function() {
126
- const buffer = new Array;
127
- return {
128
- onLoad: function(func) {
129
- buffer.push(func);
130
- },
131
-
132
- activate: function() {
133
- for(let i = 0; i < buffer.length; i++) {
134
- buffer[i].call();
135
- }
136
- },
137
-
138
- listeners: function () {
139
- const listeners = [];
140
- if (typeof Turbo !== 'undefined') {
141
- listeners.push('turbo:load', 'turbo:frame-load');
142
- } else {
143
- listeners.push('DOMContentLoaded');
144
- }
145
-
146
- return listeners;
147
- }
148
- };
149
- }();
150
-
151
- // turbo triggers turbo:load events on page transition
152
- // If app isn't using turbo, this event will never be triggered, no prob.
153
- Core.listeners().forEach(function(listener) {
154
- document.addEventListener(listener, function() {
155
- Core.activate();
156
- });
157
- });
158
-
159
- Core.onLoad(function () {
160
- const elem = document.querySelector('.no-js');
161
-
162
- // The "no-js" class may already have been removed because this function is
163
- // run on every turbo:load event, in that case, it won't find an element.
164
- if (!elem) return;
165
-
166
- elem.classList.remove('no-js');
167
- elem.classList.add('js');
168
- });
169
-
170
- /*!
171
- * Color mode toggler for Blacklight
172
- * Based on Bootstrap's color mode toggler (https://getbootstrap.com/docs/5.3/customize/color-modes/#javascript)
173
- */
174
-
175
-
176
- const ColorThemeSwitcher = (() => {
177
-
178
- const getStoredTheme = () => localStorage.getItem('theme');
179
- const setStoredTheme = theme => localStorage.setItem('theme', theme);
180
-
181
- const getPreferredTheme = () => {
182
- const storedTheme = getStoredTheme();
183
- if (storedTheme) {
184
- return storedTheme
185
- }
186
- return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
187
- };
188
-
189
- const setTheme = theme => {
190
- if (theme === 'auto') {
191
- document.documentElement.setAttribute('data-bs-theme', window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
192
- } else {
193
- document.documentElement.setAttribute('data-bs-theme', theme);
194
- }
195
- };
196
-
197
- const showActiveTheme = (theme, focus = false) => {
198
- const themeSwitcher = document.querySelector('#bl-theme-switcher');
199
- if (!themeSwitcher) return
200
-
201
- // Reset all dropdown items
202
- document.querySelectorAll('[data-bs-theme-value]').forEach(element => {
203
- element.classList.remove('active');
204
- element.setAttribute('aria-pressed', 'false');
205
- const check = element.querySelector('.bl-theme-check');
206
- if (check) check.classList.add('d-none');
207
- });
208
-
209
- // Activate the selected item
210
- const btnToActive = document.querySelector(`[data-bs-theme-value="${theme}"]`);
211
- if (btnToActive) {
212
- btnToActive.classList.add('active');
213
- btnToActive.setAttribute('aria-pressed', 'true');
214
- const check = btnToActive.querySelector('.bl-theme-check');
215
- if (check) check.classList.remove('d-none');
216
- }
217
-
218
- // Swap the toggle button icon
219
- themeSwitcher.querySelectorAll('.bl-theme-icon').forEach(icon => icon.classList.add('d-none'));
220
- const activeIcon = themeSwitcher.querySelector(`.bl-theme-icon[data-bl-theme-icon="${theme}"]`);
221
- if (activeIcon) activeIcon.classList.remove('d-none');
222
-
223
- themeSwitcher.setAttribute('aria-label', `Toggle theme (${theme})`);
135
+ const BookmarkToggle = (() => {
136
+ // change form submit toggle to checkbox
137
+ Blacklight.doBookmarkToggleBehavior = function() {
138
+ document.addEventListener('click', (e) => {
139
+ if (e.target.matches('[data-checkboxsubmit-target="checkbox"]')) {
140
+ const form = e.target.closest('form');
141
+ if (form) new CheckboxSubmit(form).clicked(e);
142
+ }
143
+ });
144
+ };
145
+ Blacklight.doBookmarkToggleBehavior.selector = 'form.bookmark-toggle';
224
146
 
225
- if (focus) {
226
- themeSwitcher.focus();
227
- }
228
- };
147
+ Blacklight.doBookmarkToggleBehavior();
148
+ })();
229
149
 
230
- window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
231
- const storedTheme = getStoredTheme();
232
- if (storedTheme !== 'light' && storedTheme !== 'dark') {
233
- setTheme(getPreferredTheme());
150
+ const ButtonFocus = (() => {
151
+ document.addEventListener('click', (e) => {
152
+ // Button clicks should change focus. As of 10/3/19, Firefox for Mac and
153
+ // Safari both do not set focus to a button on button click.
154
+ // See https://zellwk.com/blog/inconsistent-button-behavior/ for background information
155
+ if (e.target.matches('[data-toggle="collapse"]') || e.target.matches('[data-bs-toggle="collapse"]')) {
156
+ e.target.focus();
234
157
  }
235
158
  });
236
-
237
- document.addEventListener('click', e => {
238
- const btn = e.target.closest('[data-bs-theme-value]');
239
- if (!btn) return
240
-
241
- const theme = btn.getAttribute('data-bs-theme-value');
242
- setStoredTheme(theme);
243
- setTheme(theme);
244
- showActiveTheme(theme, true);
245
- });
246
-
247
- Core.onLoad(() => showActiveTheme(getPreferredTheme()));
248
-
249
- return { setTheme, getPreferredTheme, showActiveTheme }
250
159
  })();
251
160
 
252
- // Usage:
253
- // ```
254
- // const basicFunction = (entry) => console.log(entry)
255
- // const debounced = debounce(basicFunction("I should only be called once"));
256
- //
257
- // debounced // does NOT print to the screen because it is invoked again less than 200 milliseconds later
258
- // debounced // does print to the screen
259
- // ```
260
- function debounce(func, timeout = 200) {
261
- let timer;
262
- return (...args) => {
263
- clearTimeout(timer);
264
- timer = setTimeout(() => { func.apply(this, args); }, timeout);
265
- };
266
- }
267
-
268
- const FacetSuggest = async (e) => {
269
- if (e.target.matches('.facet-suggest')) {
270
- const queryFragment = e.target.value?.trim();
271
- const facetField = e.target.dataset.facetField;
272
- const facetArea = document.querySelector('.facet-extended-list');
273
- const prevNextLinks = document.querySelectorAll('.prev_next_links');
274
-
275
- if (!facetField) { return; }
276
-
277
- // Get the search params from the current query so the facet suggestions
278
- // can retain that context.
279
- const facetSearchContext = e.target.dataset.facetSearchContext;
280
- const url = new URL(facetSearchContext, window.location.origin);
281
-
282
- // Drop facet.page so a filtered suggestion list will always start on page 1
283
- url.searchParams.delete('facet.page');
284
- // add our queryFragment for facet filtering
285
- url.searchParams.append('query_fragment', queryFragment);
286
-
287
- const facetSearchParams = url.searchParams.toString();
288
- const basePathComponent = url.pathname.split('/')[1];
289
-
290
- const urlToFetch = `/${basePathComponent}/facet_suggest/${facetField}?${facetSearchParams}`;
291
-
292
- const response = await fetch(urlToFetch);
293
- if (response.ok) {
294
- const blob = await response.blob();
295
- const text = await blob.text();
296
-
297
- if (text && facetArea) {
298
- facetArea.innerHTML = text;
299
- }
300
- }
301
-
302
- // Hide the prev/next links when a user enters text in the facet
303
- // suggestion input. They don't work with a filtered list.
304
- prevNextLinks.forEach(element => {
305
- element.classList.toggle('invisible', !!queryFragment);
306
- });
307
-
308
- // Add a class to distinguish suggested facet values vs. regular.
309
- facetArea.classList.toggle('facet-suggestions', !!queryFragment);
310
- }
311
- };
312
-
313
- document.addEventListener('input', debounce(FacetSuggest));
314
-
315
161
  /*
316
162
  The blacklight modal plugin can display some interactions inside a Bootstrap
317
163
  modal window, including some multi-page interactions.
@@ -346,7 +192,7 @@ document.addEventListener('input', debounce(FacetSuggest));
346
192
 
347
193
  <div data-blacklight-modal="container">
348
194
  <div class="modal-header">
349
- <button type="button" class="btn-close" data-bl-dismiss="modal" aria-hidden="true">×</button>
195
+ <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
350
196
  <h3 class="modal-title">Request Placed</h3>
351
197
  </div>
352
198
 
@@ -357,7 +203,7 @@ document.addEventListener('input', debounce(FacetSuggest));
357
203
 
358
204
 
359
205
  <div class="modal-footer">
360
- <button type="button" class="btn btn-secondary" data-bl-dismiss="modal">Close</button>
206
+ <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
361
207
  </div>
362
208
  </div>
363
209
 
@@ -368,7 +214,13 @@ document.addEventListener('input', debounce(FacetSuggest));
368
214
  */
369
215
 
370
216
  const Modal = (() => {
371
- const modal = {};
217
+ // We keep all our data in Blacklight.modal object.
218
+ // Create lazily if someone else created first.
219
+ if (Blacklight.modal === undefined) {
220
+ Blacklight.modal = {};
221
+ }
222
+
223
+ const modal = Blacklight.modal;
372
224
 
373
225
  // a Bootstrap modal div that should be already on the page hidden
374
226
  modal.modalSelector = '#blacklight-modal';
@@ -389,66 +241,42 @@ const Modal = (() => {
389
241
  modal.containerSelector = '[data-blacklight-modal~=container]';
390
242
 
391
243
  // Called on fatal failure of ajax load, function returns content
392
- // to show to user in modal. Right now called only for network errors.
393
- modal.onFailure = function (error) {
394
- console.error('Server error:', this.url, error);
244
+ // to show to user in modal. Right now called only for extreme
245
+ // network errors.
246
+ modal.onFailure = function (jqXHR, textStatus, errorThrown) {
247
+ console.error('Server error:', this.url, jqXHR.status, errorThrown);
395
248
 
396
249
  const contents = `<div class="modal-header">
397
250
  <div class="modal-title">There was a problem with your request.</div>
398
- <button type="button" class="blacklight-modal-close btn-close" data-bl-dismiss="modal" aria-label="Close">
251
+ <button type="button" class="blacklight-modal-close btn-close close" data-dismiss="modal" data-bs-dismiss="modal" aria-label="Close">
252
+ <span aria-hidden="true">&times;</span>
399
253
  </button>
400
254
  </div>
401
255
  <div class="modal-body">
402
256
  <p>Expected a successful response from the server, but got an error</p>
403
- <pre>${this.url}\n${error}</pre>
257
+ <pre>${this.type} ${this.url}\n${jqXHR.status}: ${errorThrown}</pre>
404
258
  </div>`;
405
259
 
406
- modal.target().querySelector('.modal-content').innerHTML = contents;
260
+ document.querySelector(`${modal.modalSelector} .modal-content`).innerHTML = contents;
407
261
 
408
262
  modal.show();
409
263
  };
410
264
 
411
265
  // Add the passed in contents to the modal and display it.
412
- // We have specific handling so that scripts returned from the ajax call are executed.
413
- // This enables adding a script like recaptcha to prevent bots from sending emails.
414
- modal.receiveAjax = function (contents) {
415
- const domparser = new DOMParser();
416
- const dom = domparser.parseFromString(contents, "text/html");
417
- // If there is a containerSelector on the document, use its children.
418
- let elements = dom.querySelectorAll(`${modal.containerSelector} > *`);
419
- const frag = document.createDocumentFragment();
420
- if (elements.length == 0) {
421
- // If the containerSelector wasn't found, use the whole document
422
- elements = dom.body.childNodes;
423
- }
424
- elements.forEach((el) => frag.appendChild(el));
425
- modal.activateScripts(frag);
426
-
427
- modal.target().querySelector('.modal-content').replaceChildren(frag);
428
-
429
- // send custom event with the modal dialog div as the target
430
- var e = new CustomEvent('loaded.blacklight.blacklight-modal', { bubbles: true, cancelable: true });
431
- modal.target().dispatchEvent(e);
266
+ modal.receiveAjax = function (contents) {
267
+ const domparser = new DOMParser();
268
+ const dom = domparser.parseFromString(contents, "text/html");
269
+ const elements = dom.querySelectorAll(`${modal.containerSelector} > *`);
270
+ document.querySelector(`${modal.modalSelector} .modal-content`).replaceChildren(...elements);
432
271
 
433
- // if they did preventDefault, don't show the dialog
434
- if (e.defaultPrevented) return;
435
- modal.show();
272
+ modal.show();
436
273
  };
437
274
 
438
- // DOMParser doesn't allow scripts to be executed. This fixes that.
439
- modal.activateScripts = function (frag) {
440
- frag.querySelectorAll('script').forEach((script) => {
441
- const fixedScript = document.createElement('script');
442
- fixedScript.src = script.src;
443
- fixedScript.async = false;
444
- script.parentNode.replaceChild(fixedScript, script);
445
- });
446
- };
447
275
 
448
276
  modal.modalAjaxLinkClick = function(e) {
449
277
  e.preventDefault();
450
- const href = e.target.closest('a').getAttribute('href');
451
- fetch(href, { headers: { 'X-Requested-With': 'XMLHttpRequest' }})
278
+ const href = e.target.getAttribute('href');
279
+ fetch(href)
452
280
  .then(response => {
453
281
  if (!response.ok) {
454
282
  throw new TypeError("Request failed");
@@ -460,136 +288,96 @@ const Modal = (() => {
460
288
  };
461
289
 
462
290
  modal.setupModal = function() {
463
- // Register several click handlers in ONE event handler for efficiency
464
- //
465
- // * close button OR click on backdrop (modal.modalSelector) closes modal
466
- // * trigger and preserve link in modal functionality -- if somethign matches both trigger and
467
- // preserve, still only called once.
291
+ // Register both trigger and preserve selectors in ONE event handler, combining
292
+ // into one selector with a comma, so if something matches BOTH selectors, it
293
+ // still only gets the event handler called once.
468
294
  document.addEventListener('click', (e) => {
469
- if (e.target.closest(`${modal.triggerLinkSelector}, ${modal.preserveLinkSelector}`))
295
+ if (e.target.matches(`${modal.triggerLinkSelector}, ${modal.preserveLinkSelector}`))
470
296
  modal.modalAjaxLinkClick(e);
471
- else if (e.target.matches(`${modal.modalSelector}`) || e.target.closest('[data-bl-dismiss="modal"]'))
297
+ else if (e.target.matches('[data-bl-dismiss="modal"]'))
472
298
  modal.hide();
473
299
  });
474
-
475
- // Make sure user-agent dismissal of html 'dialog', etc `esc` key, triggers
476
- // our hide logic, including events and scroll restoration.
477
- const modalDom = modal.target();
478
- if (modalDom) {
479
- modal.target().addEventListener('cancel', (e) => {
480
- e.preventDefault(); // 'hide' will close the modal unless cancelled
481
-
482
- modal.hide();
483
- });
484
- }
485
300
  };
486
301
 
487
302
  modal.hide = function (el) {
488
- const dom = modal.target();
303
+ const dom = document.querySelector(Blacklight.modal.modalSelector);
489
304
 
490
305
  if (!dom.open) return
491
-
492
- var e = new CustomEvent('hide.blacklight.blacklight-modal', { bubbles: true, cancelable: true });
493
- dom.dispatchEvent(e);
494
-
495
306
  dom.close();
496
-
497
- // Turn body scrolling back to what it was
498
- document.body.style["overflow"] = modal.originalBodyOverflow;
499
- document.body.style["padding-right"] = modal.originalBodyPaddingRight;
500
- modal.originalBodyOverflow = undefined;
501
- modal.originalBodyPaddingRight = undefined;
502
307
  };
503
308
 
504
309
  modal.show = function(el) {
505
- const dom = modal.target();
310
+ const dom = document.querySelector(Blacklight.modal.modalSelector);
506
311
 
507
312
  if (dom.open) return
508
-
509
- var e = new CustomEvent('show.blacklight.blacklight-modal', { bubbles: true, cancelable: true });
510
- dom.dispatchEvent(e);
511
-
512
313
  dom.showModal();
513
-
514
- // Turn off body scrolling
515
- modal.originalBodyOverflow = document.body.style['overflow'];
516
- modal.originalBodyPaddingRight = document.body.style['padding-right'];
517
- document.body.style["overflow"] = "hidden";
518
- document.body.style["padding-right"] = "0px";
519
- };
520
-
521
- modal.target = function() {
522
- return document.querySelector(modal.modalSelector);
523
314
  };
524
315
 
525
316
  modal.setupModal();
526
-
527
- return modal;
528
317
  })();
529
318
 
530
- const SearchContext = (e) => {
531
- const contextLink = e.target.closest('[data-context-href]');
532
- if (contextLink) {
533
- SearchContext.handleSearchContextMethod.call(contextLink, e);
534
- }
535
- };
319
+ const SearchContext = (() => {
320
+ Blacklight.doSearchContextBehavior = function() {
321
+ document.addEventListener('click', (e) => {
322
+ if (e.target.matches('[data-context-href]')) {
323
+ Blacklight.handleSearchContextMethod.call(e.target, e);
324
+ }
325
+ });
326
+ };
536
327
 
537
- SearchContext.csrfToken = () => document.querySelector('meta[name=csrf-token]')?.content;
538
- SearchContext.csrfParam = () => document.querySelector('meta[name=csrf-param]')?.content;
328
+ Blacklight.csrfToken = () => document.querySelector('meta[name=csrf-token]')?.content;
329
+ Blacklight.csrfParam = () => document.querySelector('meta[name=csrf-param]')?.content;
539
330
 
540
- // this is the Rails.handleMethod with a couple adjustments, described inline:
541
- // first, we're attaching this directly to the event handler, so we can check for meta-keys
542
- SearchContext.handleSearchContextMethod = function(event) {
543
- const link = this;
331
+ // this is the Rails.handleMethod with a couple adjustments, described inline:
332
+ // first, we're attaching this directly to the event handler, so we can check for meta-keys
333
+ Blacklight.handleSearchContextMethod = function(event) {
334
+ const link = this;
544
335
 
545
- // instead of using the normal href, we need to use the context href instead
546
- let href = link.getAttribute('data-context-href');
547
- let target = link.getAttribute('target');
548
- let csrfToken = SearchContext.csrfToken();
549
- let csrfParam = SearchContext.csrfParam();
550
- let form = document.createElement('form');
551
- form.method = 'post';
552
- form.action = href;
336
+ // instead of using the normal href, we need to use the context href instead
337
+ let href = link.getAttribute('data-context-href');
338
+ let target = link.getAttribute('target');
339
+ let csrfToken = Blacklight.csrfToken();
340
+ let csrfParam = Blacklight.csrfParam();
341
+ let form = document.createElement('form');
342
+ form.method = 'post';
343
+ form.action = href;
553
344
 
554
345
 
555
- let formContent = `<input name="_method" value="post" type="hidden" />
556
- <input name="redirect" value="${link.getAttribute('href')}" type="hidden" />`;
346
+ let formContent = `<input name="_method" value="post" type="hidden" />
347
+ <input name="redirect" value="${link.getAttribute('href')}" type="hidden" />`;
557
348
 
558
- // check for meta keys.. if set, we should open in a new tab
559
- if(event.metaKey || event.ctrlKey) {
560
- form.dataset.turbo = "false";
561
- target = '_blank';
562
- }
349
+ // check for meta keys.. if set, we should open in a new tab
350
+ if(event.metaKey || event.ctrlKey) {
351
+ target = '_blank';
352
+ }
563
353
 
564
- if (csrfParam !== undefined && csrfToken !== undefined) {
565
- formContent += `<input name="${csrfParam}" value="${csrfToken}" type="hidden" />`;
566
- }
354
+ if (csrfParam !== undefined && csrfToken !== undefined) {
355
+ formContent += `<input name="${csrfParam}" value="${csrfToken}" type="hidden" />`;
356
+ }
567
357
 
568
- // Must trigger submit by click on a button, else "submit" event handler won't work!
569
- // https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/submit
570
- formContent += '<input type="submit" />';
358
+ // Must trigger submit by click on a button, else "submit" event handler won't work!
359
+ // https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/submit
360
+ formContent += '<input type="submit" />';
571
361
 
572
- if (target) { form.setAttribute('target', target); }
362
+ if (target) { form.setAttribute('target', target); }
573
363
 
574
- form.style.display = 'none';
575
- form.innerHTML = formContent;
576
- document.body.appendChild(form);
577
- form.querySelector('[type="submit"]').click();
364
+ form.style.display = 'none';
365
+ form.innerHTML = formContent;
366
+ document.body.appendChild(form);
367
+ form.querySelector('[type="submit"]').click();
578
368
 
579
- event.preventDefault();
580
- };
369
+ event.preventDefault();
370
+ };
581
371
 
582
- document.addEventListener('click', SearchContext);
372
+ Blacklight.doSearchContextBehavior();
373
+ })();
583
374
 
584
375
  const index = {
585
376
  BookmarkToggle,
586
377
  ButtonFocus,
587
- ColorThemeSwitcher,
588
- FacetSuggest,
589
378
  Modal,
590
379
  SearchContext,
591
- Core,
592
- onLoad: Core.onLoad
380
+ onLoad: Blacklight.onLoad
593
381
  };
594
382
 
595
383
  export { index as default };