geoblacklight 6.0.0.pre.alpha.7 → 6.0.0.pre.beta.2

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 (231) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +14 -3
  3. data/README.md +2 -2
  4. data/Rakefile +1 -17
  5. data/app/assets/images/geoblacklight/logo-dark.svg +31 -0
  6. data/app/assets/images/geoblacklight/logo.svg +10 -10
  7. data/app/assets/stylesheets/geoblacklight/global.css +44 -7
  8. data/app/assets/stylesheets/geoblacklight/index_maps.css +0 -7
  9. data/app/assets/stylesheets/geoblacklight/record.css +33 -9
  10. data/app/assets/stylesheets/geoblacklight/search.css +66 -17
  11. data/app/assets/stylesheets/geoblacklight/viewers.css +18 -111
  12. data/app/assets/stylesheets/geoblacklight.css +0 -5
  13. data/app/components/blacklight/icons/georeferenced_component.rb +23 -0
  14. data/app/components/geoblacklight/document/download_link_component.html.erb +1 -1
  15. data/app/components/geoblacklight/document/preview_component.html.erb +0 -2
  16. data/app/components/geoblacklight/document_component.html.erb +0 -4
  17. data/app/components/geoblacklight/facets/bbox_field_component.html.erb +2 -1
  18. data/app/components/geoblacklight/georeferenced_header_badge_component.rb +16 -0
  19. data/app/components/geoblacklight/header_badge_component.html.erb +4 -2
  20. data/app/components/geoblacklight/header_badge_component.rb +1 -1
  21. data/app/components/geoblacklight/header_badges_component.html.erb +5 -0
  22. data/app/components/geoblacklight/header_badges_component.rb +34 -0
  23. data/app/components/geoblacklight/iiif_drag_drop_component.html.erb +1 -1
  24. data/app/components/geoblacklight/item_map_viewer_component.html.erb +0 -58
  25. data/app/components/geoblacklight/item_map_viewer_component.rb +19 -70
  26. data/app/components/geoblacklight/locator_map_component.rb +31 -0
  27. data/app/components/geoblacklight/login_link_component.html.erb +1 -1
  28. data/app/components/geoblacklight/login_link_component.rb +17 -1
  29. data/app/components/geoblacklight/metadata_description_markdown_component.rb +3 -9
  30. data/app/components/geoblacklight/overview_map_component.html.erb +2 -0
  31. data/app/components/geoblacklight/overview_map_component.rb +86 -0
  32. data/app/components/geoblacklight/relations/relation_component.html.erb +12 -0
  33. data/app/components/geoblacklight/relations/relation_component.rb +30 -0
  34. data/app/components/geoblacklight/relations/relations_component.html.erb +15 -0
  35. data/app/components/geoblacklight/relations/relations_component.rb +59 -0
  36. data/app/components/geoblacklight/resource_header_badge_component.rb +1 -1
  37. data/app/components/geoblacklight/search_result_component.html.erb +14 -33
  38. data/app/components/geoblacklight/search_result_component.rb +2 -14
  39. data/app/components/geoblacklight/static_map_component.rb +3 -14
  40. data/app/components/geoblacklight/truncatable_metadata_field_layout_component.html.erb +7 -0
  41. data/app/components/geoblacklight/truncatable_metadata_field_layout_component.rb +45 -0
  42. data/app/controllers/{relation_controller.rb → relations_controller.rb} +4 -2
  43. data/app/controllers/viewer_record_controller.rb +28 -0
  44. data/app/helpers/geoblacklight_helper.rb +57 -6
  45. data/app/javascript/geoblacklight/controllers/overview_map_controller.js +143 -0
  46. data/app/javascript/geoblacklight/core.js +8 -10
  47. data/app/javascript/geoblacklight/index.js +9 -12
  48. data/app/javascript/geoblacklight/initializers/field_truncation.js +62 -0
  49. data/app/javascript/geoblacklight/initializers/metadata_download.js +3 -8
  50. data/app/javascript/geoblacklight/initializers/truncation.js +7 -3
  51. data/app/javascript/geoblacklight/initializers/viewer_requests.js +61 -0
  52. data/app/javascript/geoblacklight/initializers/viewer_theme.js +28 -0
  53. data/app/models/concerns/geoblacklight/solr_document/thumbnail.rb +38 -0
  54. data/app/models/concerns/geoblacklight/solr_document.rb +2 -0
  55. data/app/models/concerns/geoblacklight/suppressed_records_search_behavior.rb +1 -1
  56. data/app/views/catalog/_document_split.html.erb +10 -10
  57. data/app/views/catalog/_home_text.html.erb +1 -1
  58. data/app/views/catalog/metadata.html.erb +1 -1
  59. data/app/views/{relation → relations}/index.html.erb +1 -1
  60. data/app/views/relations/index.json.jbuilder +9 -0
  61. data/config/importmap.rb +8 -8
  62. data/config/locales/geoblacklight.en.yml +48 -99
  63. data/geoblacklight.gemspec +3 -3
  64. data/lib/generators/geoblacklight/assets_generator.rb +2 -2
  65. data/lib/generators/geoblacklight/install_generator.rb +3 -6
  66. data/lib/generators/geoblacklight/templates/assets/customizations.css +5 -1
  67. data/lib/generators/geoblacklight/templates/catalog_controller.rb +17 -27
  68. data/lib/generators/geoblacklight/templates/settings.yml +15 -95
  69. data/lib/geoblacklight/configuration/display_note_shown_config.rb +3 -0
  70. data/lib/geoblacklight/configuration/relationship_config.rb +7 -1
  71. data/lib/geoblacklight/configuration/relationships_config.rb +15 -15
  72. data/lib/geoblacklight/configuration/settings_attributes.rb +85 -0
  73. data/lib/geoblacklight/configuration/settings_builder.rb +3 -14
  74. data/lib/geoblacklight/configuration.rb +23 -62
  75. data/lib/geoblacklight/exceptions.rb +4 -0
  76. data/lib/geoblacklight/reference.rb +0 -2
  77. data/lib/geoblacklight/references.rb +17 -5
  78. data/lib/geoblacklight/relations/ancestors.rb +12 -0
  79. data/lib/geoblacklight/relations/descendants.rb +11 -0
  80. data/lib/geoblacklight/relations/query.rb +39 -0
  81. data/lib/geoblacklight/{relation → relations}/relation_response.rb +5 -4
  82. data/lib/geoblacklight/routes/exportable.rb +2 -1
  83. data/lib/geoblacklight/version.rb +1 -1
  84. data/lib/geoblacklight/viewer_record.rb +39 -0
  85. data/lib/geoblacklight.rb +1 -1
  86. data/lib/tasks/geoblacklight.rake +1 -17
  87. data/lib/tasks/solr.rb +37 -0
  88. data/schema/readme.md +1 -1
  89. data/script/wait-for-solr +36 -0
  90. data/solr/conf/solrconfig.xml +10 -16
  91. data/spec/components/geoblacklight/document/sidebar_component_spec.rb +3 -3
  92. data/spec/components/geoblacklight/document_component_spec.rb +8 -34
  93. data/spec/components/geoblacklight/{header_icons_component_spec.rb → header_badges_component_spec.rb} +20 -2
  94. data/spec/components/geoblacklight/item_map_viewer_component_spec.rb +65 -15
  95. data/spec/components/geoblacklight/locator_map_component_spec.rb +54 -0
  96. data/spec/components/geoblacklight/login_link_component_spec.rb +20 -12
  97. data/spec/components/geoblacklight/metadata_description_markdown_component_spec.rb +1 -6
  98. data/spec/components/geoblacklight/overview_map_component_spec.rb +136 -0
  99. data/spec/components/geoblacklight/relations/relation_component_spec.rb +98 -0
  100. data/spec/components/geoblacklight/relations/relations_component_spec.rb +146 -0
  101. data/spec/components/geoblacklight/search_result_component_spec.rb +66 -39
  102. data/spec/components/geoblacklight/static_map_component_spec.rb +8 -2
  103. data/spec/components/geoblacklight/truncatable_metadata_field_layout_component_spec.rb +83 -0
  104. data/spec/controllers/catalog_controller_spec.rb +22 -7
  105. data/spec/controllers/{relation_controller_spec.rb → relations_controller_spec.rb} +1 -1
  106. data/spec/factories/user.rb +6 -1
  107. data/spec/features/axe_spec.rb +5 -3
  108. data/spec/features/home_page_spec.rb +8 -7
  109. data/spec/features/index_view_spec.rb +6 -20
  110. data/spec/features/layer_preview_spec.rb +4 -11
  111. data/spec/features/locator_map_spec.rb +31 -0
  112. data/spec/features/relations_spec.rb +22 -11
  113. data/spec/features/restricted_viewer_spec.rb +14 -0
  114. data/spec/features/search_results_map_spec.rb +89 -13
  115. data/spec/features/search_spec.rb +6 -2
  116. data/spec/features/sign_in_spec.rb +26 -0
  117. data/spec/features/tilejson_spec.rb +1 -3
  118. data/spec/features/tms_spec.rb +2 -2
  119. data/spec/features/truncated_metadata_spec.rb +77 -0
  120. data/spec/features/viewer_requests_spec.rb +40 -0
  121. data/spec/features/viewer_theme_spec.rb +51 -0
  122. data/spec/features/wmts_spec.rb +6 -6
  123. data/spec/features/xyz_spec.rb +3 -3
  124. data/spec/fixtures/solr_documents/README.md +18 -14
  125. data/spec/fixtures/solr_documents/actual-polygon1.json +22 -18
  126. data/spec/fixtures/solr_documents/b1g_wabash_child_15.json +14 -15
  127. data/spec/fixtures/solr_documents/b1g_wabash_child_16.json +14 -15
  128. data/spec/fixtures/solr_documents/b1g_wabash_child_17.json +14 -15
  129. data/spec/fixtures/solr_documents/b1g_wabash_child_18.json +14 -15
  130. data/spec/fixtures/solr_documents/b1g_wabash_parent.json +14 -15
  131. data/spec/fixtures/solr_documents/esri-dynamic-layer-single-layer.json +2 -2
  132. data/spec/fixtures/solr_documents/esri-feature-layer.json +1 -1
  133. data/spec/fixtures/solr_documents/esri-image-map-layer.json +20 -20
  134. data/spec/fixtures/solr_documents/esri-wms-layer.json +22 -24
  135. data/spec/fixtures/solr_documents/index_map_point.json +3 -3
  136. data/spec/fixtures/solr_documents/public_polygon.json +28 -0
  137. data/spec/helpers/geoblacklight_helper_spec.rb +103 -25
  138. data/spec/lib/geoblacklight/bounding_box_spec.rb +16 -0
  139. data/spec/lib/geoblacklight/configuration/relationships_config_spec.rb +121 -0
  140. data/spec/lib/geoblacklight/configuration/settings_attributes_spec.rb +113 -0
  141. data/spec/lib/geoblacklight/configuration/settings_builder_spec.rb +33 -4
  142. data/spec/lib/geoblacklight/references_spec.rb +35 -0
  143. data/spec/lib/geoblacklight/{relation → relations}/ancestors_spec.rb +17 -6
  144. data/spec/lib/geoblacklight/{relation → relations}/descendants_spec.rb +14 -7
  145. data/spec/lib/geoblacklight/{relation → relations}/relation_response_spec.rb +31 -17
  146. data/spec/lib/geoblacklight/viewer_record_spec.rb +69 -0
  147. data/spec/models/concerns/geoblacklight/solr_document/thumbnail_spec.rb +149 -0
  148. data/spec/models/concerns/geoblacklight/solr_document_spec.rb +1 -1
  149. data/spec/requests/bookmarks_spec.rb +2 -1
  150. data/spec/requests/catalog_show_spec.rb +24 -2
  151. data/spec/requests/index_view_spec.rb +50 -2
  152. data/spec/requests/missing_metadata_spec.rb +1 -1
  153. data/spec/requests/relations_spec.rb +9 -2
  154. data/spec/requests/search_results_spec.rb +6 -6
  155. data/spec/requests/viewer_record_spec.rb +37 -0
  156. data/spec/requests/viewer_requests_spec.rb +52 -0
  157. data/spec/solr_config_spec.rb +41 -0
  158. data/spec/solr_fixtures_spec.rb +23 -0
  159. data/spec/spec_helper.rb +13 -3
  160. data/spec/support/authentication.rb +37 -0
  161. data/spec/support/features/map_helpers.rb +68 -0
  162. data/spec/support/features/session_helpers.rb +18 -13
  163. data/spec/support/features/viewer_helpers.rb +20 -0
  164. data/spec/support/features.rb +4 -0
  165. data/spec/test_app_templates/lib/generators/test_app_generator.rb +1 -1
  166. data/template.rb +1 -1
  167. metadata +72 -84
  168. data/app/components/geoblacklight/accordion_component.html.erb +0 -16
  169. data/app/components/geoblacklight/accordion_component.rb +0 -15
  170. data/app/components/geoblacklight/attribute_table_component.html.erb +0 -15
  171. data/app/components/geoblacklight/attribute_table_component.rb +0 -17
  172. data/app/components/geoblacklight/header_icons_component.html.erb +0 -3
  173. data/app/components/geoblacklight/header_icons_component.rb +0 -27
  174. data/app/components/geoblacklight/index_map_inspect_component.html.erb +0 -12
  175. data/app/components/geoblacklight/index_map_inspect_component.rb +0 -15
  176. data/app/components/geoblacklight/index_map_legend_component.html.erb +0 -14
  177. data/app/components/geoblacklight/index_map_legend_component.rb +0 -24
  178. data/app/components/geoblacklight/location_leaflet_map_component.rb +0 -68
  179. data/app/components/geoblacklight/relations_component.html.erb +0 -23
  180. data/app/components/geoblacklight/relations_component.rb +0 -25
  181. data/app/components/geoblacklight/viewer_help_text_component.html.erb +0 -1
  182. data/app/components/geoblacklight/viewer_help_text_component.rb +0 -46
  183. data/app/controllers/wms_controller.rb +0 -17
  184. data/app/javascript/geoblacklight/controllers/leaflet_viewer_controller.js +0 -240
  185. data/app/javascript/geoblacklight/controllers/openlayers_viewer_controller.js +0 -74
  186. data/app/javascript/geoblacklight/controllers/search_results_controller.js +0 -50
  187. data/app/javascript/geoblacklight/initializers/popovers.js +0 -11
  188. data/app/javascript/geoblacklight/initializers/tooltips.js +0 -51
  189. data/app/javascript/geoblacklight/leaflet/basemaps.js +0 -73
  190. data/app/javascript/geoblacklight/leaflet/constants.js +0 -18
  191. data/app/javascript/geoblacklight/leaflet/controls/geosearch.js +0 -168
  192. data/app/javascript/geoblacklight/leaflet/controls/layer_opacity.js +0 -121
  193. data/app/javascript/geoblacklight/leaflet/controls/sidebar.js +0 -49
  194. data/app/javascript/geoblacklight/leaflet/controls/sleep.js +0 -101
  195. data/app/javascript/geoblacklight/leaflet/inspection.js +0 -210
  196. data/app/javascript/geoblacklight/leaflet/layer_index_map.js +0 -128
  197. data/app/javascript/geoblacklight/leaflet/layer_wmts.js +0 -57
  198. data/app/javascript/geoblacklight/leaflet/layers.js +0 -146
  199. data/app/javascript/geoblacklight/leaflet/utils.js +0 -83
  200. data/app/javascript/geoblacklight/openlayers/basemaps.js +0 -55
  201. data/app/javascript/geoblacklight/openlayers/inspection.js +0 -42
  202. data/app/javascript/geoblacklight/openlayers/layers.js +0 -44
  203. data/app/views/relation/index.json.jbuilder +0 -8
  204. data/lib/geoblacklight/configuration/layer_config.rb +0 -28
  205. data/lib/geoblacklight/configuration/leaflet_config.rb +0 -73
  206. data/lib/geoblacklight/configuration/leaflet_layers_config.rb +0 -33
  207. data/lib/geoblacklight/configuration/leaflet_sleep_config.rb +0 -20
  208. data/lib/geoblacklight/relation/ancestors.rb +0 -31
  209. data/lib/geoblacklight/relation/descendants.rb +0 -31
  210. data/lib/geoblacklight/routes/wms.rb +0 -15
  211. data/lib/geoblacklight/wms_layer/feature_info_response.rb +0 -37
  212. data/lib/geoblacklight/wms_layer.rb +0 -34
  213. data/spec/components/geoblacklight/attribute_table_component_spec.rb +0 -36
  214. data/spec/components/geoblacklight/index_map_legend_component_spec.rb +0 -29
  215. data/spec/components/geoblacklight/viewer_help_text_component_spec.rb +0 -27
  216. data/spec/controllers/wms_controller_spec.rb +0 -34
  217. data/spec/features/configurable_basemap_spec.rb +0 -40
  218. data/spec/features/full_screen_control_spec.rb +0 -15
  219. data/spec/features/layer_inspection_spec.rb +0 -12
  220. data/spec/features/layer_opacity_spec.rb +0 -16
  221. data/spec/fixtures/solr_documents/harvard_raster.json +0 -39
  222. data/spec/fixtures/solr_documents/public_polygon_mit.json +0 -23
  223. data/spec/fixtures/solr_documents/uva_slug_colon.json +0 -29
  224. data/spec/javascripts/geoblacklight_spec.js +0 -11
  225. data/spec/lib/geoblacklight/configuration/layer_config_spec.rb +0 -71
  226. data/spec/lib/geoblacklight/configuration/leaflet_config_spec.rb +0 -129
  227. data/spec/lib/geoblacklight/configuration/leaflet_layers_config_spec.rb +0 -63
  228. data/spec/lib/geoblacklight/configuration_spec.rb +0 -48
  229. data/spec/lib/geoblacklight/wms_layer/feature_info_response_spec.rb +0 -54
  230. data/spec/lib/geoblacklight/wms_layer_spec.rb +0 -115
  231. /data/app/components/geoblacklight/{location_leaflet_map_component.html.erb → locator_map_component.html.erb} +0 -0
@@ -10,6 +10,7 @@ RSpec.describe Geoblacklight::MetadataDescriptionMarkdownComponent, type: :compo
10
10
  key: "dct_description_sm",
11
11
  label: "Description",
12
12
  render_field?: true,
13
+ layout_component: nil,
13
14
  values: ["a **short**", "description"])
14
15
  end
15
16
 
@@ -29,10 +30,4 @@ RSpec.describe Geoblacklight::MetadataDescriptionMarkdownComponent, type: :compo
29
30
  expect(page).to have_css("div.truncate-abstract p", count: 2)
30
31
  expect(page).to have_css("div.truncate-abstract p strong", text: "short")
31
32
  end
32
-
33
- describe "#markdown_to_html" do
34
- it "transforms markdown into HTML" do
35
- expect(component.markdown_to_html("a **short** description")).to eq "<p>a <strong>short</strong> description</p>\n"
36
- end
37
- end
38
33
  end
@@ -0,0 +1,136 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe Geoblacklight::OverviewMapComponent, type: :component do
6
+ let(:url) { "/catalog?q=water" }
7
+ let(:options) { {geosearch: true} }
8
+ let(:homepage_map_geom) { nil }
9
+ let(:light_basemap_url) { nil }
10
+ let(:dark_basemap_url) { nil }
11
+
12
+ subject(:map) { page.find("ogm-overview") }
13
+
14
+ before do
15
+ # Stubbed for every example, because the one that reads it renders through the hook below
16
+ allow(Geoblacklight.logger).to receive(:warn)
17
+ allow(Geoblacklight.configuration).to receive(:homepage_map_geom).and_return(homepage_map_geom)
18
+ allow(Geoblacklight.configuration).to receive(:light_basemap_url).and_return(light_basemap_url)
19
+ allow(Geoblacklight.configuration).to receive(:dark_basemap_url).and_return(dark_basemap_url)
20
+
21
+ with_controller_class(CatalogController) do
22
+ with_request_url(url) do
23
+ render_inline(described_class.new(**options))
24
+ end
25
+ end
26
+ end
27
+
28
+ it "renders an overview map that the controller can find and size" do
29
+ expect(map[:id]).to eq "overview-map"
30
+ expect(map[:class]).to eq "viewer overview-map"
31
+ expect(map["data-controller"]).to eq "overview-map"
32
+ end
33
+
34
+ it "leaves the theme to the page's color mode" do
35
+ expect(map[:theme]).to be_nil
36
+ end
37
+
38
+ describe "the basemap" do
39
+ it "is left to the viewer's own default when none is configured" do
40
+ expect(map["light-basemap"]).to be_nil
41
+ expect(map["dark-basemap"]).to be_nil
42
+ end
43
+
44
+ context "when the application configures its own" do
45
+ let(:light_basemap_url) { "https://tiles.example.edu/styles/light/style.json" }
46
+ let(:dark_basemap_url) { "https://tiles.example.edu/styles/dark/style.json" }
47
+
48
+ it "names a style document for each mode" do
49
+ expect(map["light-basemap"]).to eq "https://tiles.example.edu/styles/light/style.json"
50
+ expect(map["dark-basemap"]).to eq "https://tiles.example.edu/styles/dark/style.json"
51
+ end
52
+ end
53
+
54
+ context "when only the light-mode basemap is configured" do
55
+ let(:light_basemap_url) { "https://tiles.example.edu/styles/light/style.json" }
56
+
57
+ it "leaves dark mode to the viewer rather than reusing the light one" do
58
+ expect(map["light-basemap"]).to eq "https://tiles.example.edu/styles/light/style.json"
59
+ expect(map["dark-basemap"]).to be_nil
60
+ end
61
+ end
62
+ end
63
+
64
+ it "asks the controller for a search of the area a reader draws, and for the row a number belongs to" do
65
+ expect(map["data-action"]).to eq "boundsChange->overview-map#search highlightChange->overview-map#highlight"
66
+ expect(map["data-overview-map-catalog-url-value"]).to be_present
67
+ end
68
+
69
+ # ogm-overview keeps its map alive across a disconnect that turns out to be a reconnect rather than
70
+ # a removal, so the element carrying it can survive a search rather than being rebuilt
71
+ it "is carried over a search" do
72
+ expect(map["data-turbo-permanent"]).to be_present
73
+ end
74
+
75
+ describe "searching the map" do
76
+ it "is offered" do
77
+ expect(map[:geosearch]).to eq "true"
78
+ end
79
+
80
+ it "says how to go about it in the language the rest of the page is in" do
81
+ expect(map["search-help-text"]).to eq I18n.t("geoblacklight.map.geosearch.search_help")
82
+ end
83
+
84
+ context "when there is no searching to do" do
85
+ let(:options) { {} }
86
+
87
+ it "is left off entirely, and there is nowhere for a search to go" do
88
+ expect(map[:geosearch]).to be_nil
89
+ expect(map["search-help-text"]).to be_nil
90
+ expect(map["data-overview-map-catalog-url-value"]).to be_nil
91
+ end
92
+ end
93
+ end
94
+
95
+ # The area a search is filtered to is the other thing that says where to look; that one is in
96
+ # spec/requests/index_view_spec.rb, where the controller permits the parameter it comes from, and
97
+ # where the box beside the map that restates it for a later search is checked too - view-bounds
98
+ # doesn't need restating the same way, since the home page's default doesn't change request to
99
+ # request the way a search's bounding box does.
100
+ describe "where the map opens by default" do
101
+ context "on the home page" do
102
+ let(:url) { "/" }
103
+ let(:options) { {map_geometry: '{"type":"Polygon","coordinates":[[[-73.58,42.93],[-73.58,41.2],[-69.9,41.2],[-69.9,42.93]]]}', geosearch: true} }
104
+
105
+ it "is the box around the geometry the home page is configured to open on" do
106
+ expect(map["view-bounds"]).to eq "-73.58 41.2 -69.9 42.93"
107
+ end
108
+ end
109
+
110
+ context "when the home page's configured geometry isn't overridden by the caller" do
111
+ let(:url) { "/" }
112
+ let(:options) { {geosearch: true} }
113
+ let(:homepage_map_geom) { '{"type":"Polygon","coordinates":[[[-73.58,42.93],[-73.58,41.2],[-69.9,41.2],[-69.9,42.93]]]}' }
114
+
115
+ it "reads Geoblacklight.configuration.homepage_map_geom as its default" do
116
+ expect(map["view-bounds"]).to eq "-73.58 41.2 -69.9 42.93"
117
+ end
118
+ end
119
+
120
+ context "when the configured geometry can't be read" do
121
+ let(:url) { "/" }
122
+ let(:options) { {map_geometry: "somewhere near Boston"} }
123
+
124
+ it "is left to the map, and says so" do
125
+ expect(map["view-bounds"]).to be_nil
126
+ expect(Geoblacklight.logger).to have_received(:warn).with(/somewhere near Boston/)
127
+ end
128
+ end
129
+
130
+ context "when nothing says where to look" do
131
+ it "is left to the map, which opens on the whole world" do
132
+ expect(map["view-bounds"]).to be_nil
133
+ end
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe Geoblacklight::Relations::RelationComponent, type: :component do
6
+ let(:document) { SolrDocument.new(document_attributes) }
7
+ let(:description) { [] }
8
+ let(:document_attributes) do
9
+ {
10
+ "id" => "related-doc",
11
+ "dct_title_s" => "A Related Record",
12
+ "dct_description_sm" => description
13
+ }
14
+ end
15
+
16
+ describe "rendering the related document" do
17
+ before { render_inline(described_class.new(document: document)) }
18
+
19
+ it "links to the related document's show page" do
20
+ expect(page).to have_link("A Related Record", href: Rails.application.routes.url_helpers.solr_document_path(document))
21
+ end
22
+
23
+ it "renders the document's status icon badges" do
24
+ expect(page).to have_css(".badges")
25
+ end
26
+
27
+ it "does not render a description block when there is no description" do
28
+ expect(page).to have_no_css(".truncate-abstract")
29
+ end
30
+
31
+ it "does not render a sibling browse link when no sibling_count is given" do
32
+ expect(page).to have_no_css("a.browse-all")
33
+ end
34
+ end
35
+
36
+ context "when the document has a description" do
37
+ let(:description) { ["First paragraph.", "Second paragraph."] }
38
+
39
+ before { render_inline(described_class.new(document: document)) }
40
+
41
+ it "renders each description value as its own paragraph" do
42
+ expect(page).to have_css(".truncate-abstract p", count: 2)
43
+ expect(page).to have_content("First paragraph.")
44
+ expect(page).to have_content("Second paragraph.")
45
+ end
46
+
47
+ it "sets up the truncation data attributes for the JS initializer" do
48
+ expect(page).to have_css(
49
+ ".truncate-abstract[data-max-lines='5'][data-read-more-text='Read more'][data-close-text='Close']"
50
+ )
51
+ end
52
+ end
53
+
54
+ context "when sibling_count is nil (not an ancestor relationship)" do
55
+ before do
56
+ render_inline(described_class.new(document: document, field: "dct_isPartOf_sm", sibling_count: nil, browse_label_key: "part_of"))
57
+ end
58
+
59
+ it "does not render a sibling browse link" do
60
+ expect(page).to have_no_css("a.browse-all")
61
+ end
62
+ end
63
+
64
+ context "when sibling_count is zero (the ancestor reference doesn't resolve to anything)" do
65
+ before do
66
+ render_inline(described_class.new(document: document, field: "dct_isPartOf_sm", sibling_count: 0, browse_label_key: "part_of"))
67
+ end
68
+
69
+ it "does not render a sibling browse link" do
70
+ expect(page).to have_no_css("a.browse-all")
71
+ end
72
+ end
73
+
74
+ context "when sibling_count is one (the current document is the only one that matches)" do
75
+ before do
76
+ render_inline(described_class.new(document: document, field: "dct_isPartOf_sm", sibling_count: 1, browse_label_key: "part_of"))
77
+ end
78
+
79
+ it "does not render a sibling browse link, since the search would only return this document" do
80
+ expect(page).to have_no_css("a.browse-all")
81
+ end
82
+ end
83
+
84
+ context "when sibling_count is greater than one" do
85
+ before do
86
+ render_inline(described_class.new(document: document, field: "dct_isPartOf_sm", sibling_count: 4, browse_label_key: "part_of"))
87
+ end
88
+
89
+ it "renders a sibling browse link scoped to this document's id on the given field" do
90
+ expected_href = Rails.application.routes.url_helpers.search_catalog_path(f: {"dct_isPartOf_sm" => ["related-doc"]})
91
+ expect(page).to have_css("a.browse-all[href='#{expected_href}']")
92
+ end
93
+
94
+ it "renders the browse link text from the browse_label_key locale scope, matching the search's true total" do
95
+ expect(page).to have_link(I18n.t("geoblacklight.relations.browse.part_of", count: 4), class: "browse-all")
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,146 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe Geoblacklight::Relations::RelationsComponent, type: :component do
6
+ let(:repository) { Blacklight::Solr::Repository.new(CatalogController.blacklight_config) }
7
+ let(:relations) { Geoblacklight::Relations::RelationResponse.new(id, repository) }
8
+ let(:rel_type_info) { Geoblacklight.configuration.relationships_shown[relationship_type] }
9
+ let(:component) { described_class.new(relations: relations, relationship_type: relationship_type, rel_type_info: rel_type_info) }
10
+
11
+ describe "#render?" do
12
+ context "with a document that has matching relations" do
13
+ let(:id) { "nyu_2451_34502" }
14
+ let(:relationship_type) { :source_ancestors }
15
+
16
+ it "is true" do
17
+ expect(component.render?).to be true
18
+ end
19
+ end
20
+
21
+ context "with a document that has no matching relations" do
22
+ let(:id) { "berkeley-s7pq31" }
23
+ let(:relationship_type) { :source_ancestors }
24
+
25
+ it "is false, so the component renders nothing" do
26
+ expect(component.render?).to be false
27
+ end
28
+ end
29
+ end
30
+
31
+ describe "#browse_label_key" do
32
+ let(:id) { "nyu_2451_34502" }
33
+
34
+ it "strips the _ancestors suffix" do
35
+ expect(described_class.new(relations: relations, relationship_type: :part_of_ancestors, rel_type_info: Geoblacklight.configuration.relationships_shown.part_of_ancestors).browse_label_key).to eq("part_of")
36
+ end
37
+
38
+ it "strips the _descendants suffix" do
39
+ expect(described_class.new(relations: relations, relationship_type: :part_of_descendants, rel_type_info: Geoblacklight.configuration.relationships_shown.part_of_descendants).browse_label_key).to eq("part_of")
40
+ end
41
+ end
42
+
43
+ describe "#sibling_count" do
44
+ context "for an ancestor relationship" do
45
+ let(:relationship_type) { :source_ancestors }
46
+
47
+ context "when the current document is the only one that shares this ancestor" do
48
+ let(:id) { "nyu_2451_34502" }
49
+ let(:ancestor) { SolrDocument.new("id" => "nyu_2451_34636") }
50
+
51
+ it "counts just the current document itself" do
52
+ expect(component.sibling_count(ancestor)).to eq(1)
53
+ end
54
+ end
55
+
56
+ context "when other documents also share this ancestor" do
57
+ let(:id) { "757d0f6e-2e04-4ac1-bd28-a5204df46ac1" }
58
+ let(:relationship_type) { :part_of_ancestors }
59
+ let(:ancestor) { SolrDocument.new("id" => "eee6150b-ce2f-4837-9d17-ce72a0c1c26f") }
60
+
61
+ it "returns the total number of documents that share that ancestor, including this one" do
62
+ expect(component.sibling_count(ancestor)).to eq(4)
63
+ end
64
+ end
65
+
66
+ context "with an ancestor id containing Solr special characters" do
67
+ let(:id) { "nyu_2451_34502" }
68
+ let(:ancestor) { SolrDocument.new("id" => "ark:/12345/x6") }
69
+
70
+ it "escapes the id instead of raising" do
71
+ expect { component.sibling_count(ancestor) }.not_to raise_error
72
+ expect(component.sibling_count(ancestor)).to be_a(Integer)
73
+ end
74
+ end
75
+ end
76
+
77
+ context "for a descendant relationship" do
78
+ let(:id) { "nyu_2451_34502" }
79
+ let(:relationship_type) { :source_descendants }
80
+ let(:ancestor) { SolrDocument.new("id" => "nyu_2451_34636") }
81
+
82
+ it "returns nil, since there is nothing to browse to from a descendant" do
83
+ expect(component.sibling_count(ancestor)).to be_nil
84
+ end
85
+ end
86
+ end
87
+
88
+ describe "rendering" do
89
+ context "when there are 3 or fewer related documents" do
90
+ let(:id) { "nyu_2451_34502" }
91
+ let(:relationship_type) { :source_ancestors }
92
+
93
+ before { render_inline(component) }
94
+
95
+ it "renders the pluralized relationship label with the result count" do
96
+ expect(page).to have_css(".card-header h2", text: "Sourced from 2 items")
97
+ end
98
+
99
+ it "renders one row per related document" do
100
+ expect(page).to have_css(".list-group-item", count: 2)
101
+ end
102
+
103
+ it "does not render a browse-all footer" do
104
+ expect(page).to have_no_css(".card-footer")
105
+ end
106
+ end
107
+
108
+ context "when there are more than 3 related documents, but the relationship is an ancestor relationship" do
109
+ # browse_all_path always filters on the current document's own id, which only finds
110
+ # results for descendant relationships - there's no fixture with >3 real ancestors of
111
+ # one type, so the scenario is forced here to prove the footer is suppressed rather
112
+ # than linking to a query that would return the wrong (or zero) results.
113
+ let(:id) { "nyu_2451_34502" }
114
+ let(:relationship_type) { :source_ancestors }
115
+
116
+ before do
117
+ allow(component).to receive(:result_count).and_return(5)
118
+ render_inline(component)
119
+ end
120
+
121
+ it "does not render a browse-all footer, since browse_all_path would search the wrong direction" do
122
+ expect(page).to have_no_css(".card-footer")
123
+ end
124
+ end
125
+
126
+ context "when there are more than 3 related documents" do
127
+ let(:id) { "eee6150b-ce2f-4837-9d17-ce72a0c1c26f" }
128
+ let(:relationship_type) { :part_of_descendants }
129
+
130
+ before { render_inline(component) }
131
+
132
+ it "renders the pluralized relationship label with the result count" do
133
+ expect(page).to have_css(".card-header h2", text: "Has 4 parts")
134
+ end
135
+
136
+ it "renders only the first 3 related documents" do
137
+ expect(page).to have_css(".list-group-item", count: 3)
138
+ end
139
+
140
+ it "renders a browse-all footer linking to the rest of the results" do
141
+ expected_href = Rails.application.routes.url_helpers.search_catalog_path(f: {"dct_isPartOf_sm" => ["eee6150b-ce2f-4837-9d17-ce72a0c1c26f"]})
142
+ expect(page).to have_css(".card-footer a[href='#{expected_href}']", text: "Browse all 4 parts of this item")
143
+ end
144
+ end
145
+ end
146
+ end
@@ -4,63 +4,90 @@ require "spec_helper"
4
4
 
5
5
  RSpec.describe Geoblacklight::SearchResultComponent, type: :component do
6
6
  let(:request_context) { double(document_index_view_type: "list", action_name: :index) }
7
- let(:blacklight_config) do
8
- Blacklight::Configuration.new.configure do |config|
9
- config.add_index_field "gbl_wxsIdentifier_s"
10
- config.add_index_field "index_display"
11
- config.add_index_field "period"
12
- config.add_index_field "multi_display"
13
- end
14
- end
7
+ let(:blacklight_config) { Blacklight::Configuration.new }
15
8
  let(:presenter) do
16
9
  Blacklight::DocumentPresenter.new(document, request_context, blacklight_config)
17
10
  end
18
11
 
19
- let(:document) do
20
- SolrDocument.new(
21
- id: 1,
22
- gbl_wxsIdentifier_s: "druid:abc123",
23
- non_index_field: "do not render",
24
- period: "Ends with period.",
25
- multi_display: %w[blue blah]
26
- )
27
- end
12
+ let(:document) { SolrDocument.new(id: 1, dct_description_sm: description) }
13
+ let(:description) { [] }
14
+
28
15
  before do
29
- allow(request_context).to receive(:snippit)
30
- allow_any_instance_of(BlacklightHelper).to receive(:link_to_document)
16
+ allow_any_instance_of(BlacklightHelper).to receive(:link_to_document) do |_instance, _doc, value = nil, *|
17
+ value
18
+ end
31
19
  allow_any_instance_of(GeoblacklightHelper).to receive(:blacklight_config).and_return(blacklight_config)
32
20
  render_inline(described_class.new(document: presenter))
33
21
  end
34
22
 
35
- describe "#index_fields_display" do
36
- let(:multi_valued_text) { document["multi_display"].join(" and ") }
37
- let(:combined_fields) { document["gbl_wxsIdentifier_s"] + ". " + document["period"] }
23
+ describe "#description" do
24
+ it "does not render a description block when there is no description" do
25
+ expect(page).to have_no_css(".truncate-abstract")
26
+ end
27
+
28
+ context "when the document has a description" do
29
+ let(:description) { ["First paragraph.", "Second paragraph."] }
30
+
31
+ it "renders each description value as its own paragraph" do
32
+ expect(page).to have_css(".truncate-abstract p", count: 2)
33
+ expect(page).to have_content("First paragraph.")
34
+ expect(page).to have_content("Second paragraph.")
35
+ end
38
36
 
39
- subject(:index_fields_display) { page.find("[itemprop=description]").text }
37
+ it "sets up the truncation data attributes for the JS initializer" do
38
+ expect(page).to have_css(
39
+ ".truncate-abstract[data-max-lines='4'][data-read-more-text='Read more'][data-close-text='Close']"
40
+ )
41
+ end
40
42
 
41
- context "with multi-valued field" do
42
- it "each value is separated by comma" do
43
- expect(index_fields_display).to include(multi_valued_text)
43
+ it "exposes the description as schema.org markup" do
44
+ expect(page).to have_css(".truncate-abstract[itemprop='description']")
44
45
  end
45
46
  end
46
- context "with document fields not configured as index field" do
47
- it "does not render" do
48
- expect(index_fields_display).not_to include(document["non_index_field"])
47
+ end
48
+
49
+ describe "thumbnails" do
50
+ let(:blacklight_config) do
51
+ Blacklight::Configuration.new.configure do |config|
52
+ config.index.thumbnail_method = :geoblacklight_thumbnail
53
+ config.index.default_thumbnail = :geoblacklight_default_thumbnail
49
54
  end
50
55
  end
51
- context "with multiple document index fields present" do
52
- it "separates fields by period followed by a space" do
53
- expect(index_fields_display).to include(combined_fields)
56
+ let(:presenter) do
57
+ Blacklight::IndexPresenter.new(document, request_context, blacklight_config)
58
+ end
59
+
60
+ context "when a thumbnail is available" do
61
+ let(:request_context) do
62
+ double(document_index_view_type: "list", action_name: :index,
63
+ geoblacklight_thumbnail: '<img src="http://example.com/thumb.jpg" alt="">'.html_safe)
54
64
  end
55
- context "with index field ending in period" do
56
- it "renders only 1 period" do
57
- expect(index_fields_display).to include(document["period"] + " ")
58
- end
65
+
66
+ it "renders the thumbnail image" do
67
+ expect(page).to have_css ".document-thumbnail img[src='http://example.com/thumb.jpg']"
59
68
  end
60
69
  end
61
- context "with document empty configured index field" do
62
- it "does not render a period followed by a space" do
63
- expect(index_fields_display).not_to include(". .")
70
+
71
+ context "when no thumbnail is available but a default exists" do
72
+ let(:request_context) do
73
+ double(document_index_view_type: "list", action_name: :index,
74
+ geoblacklight_thumbnail: nil,
75
+ geoblacklight_default_thumbnail: '<span class="blacklight-icons"></span>'.html_safe)
76
+ end
77
+
78
+ it "renders the default thumbnail" do
79
+ expect(page).to have_css ".document-thumbnail .blacklight-icons"
80
+ end
81
+ end
82
+
83
+ context "when neither a thumbnail nor a default is available" do
84
+ let(:request_context) do
85
+ double(document_index_view_type: "list", action_name: :index,
86
+ geoblacklight_thumbnail: nil, geoblacklight_default_thumbnail: nil)
87
+ end
88
+
89
+ it "does not render a thumbnail" do
90
+ expect(page).not_to have_css ".document-thumbnail"
64
91
  end
65
92
  end
66
93
  end
@@ -15,8 +15,14 @@ RSpec.describe Geoblacklight::StaticMapComponent, type: :component do
15
15
  end
16
16
 
17
17
  context "when the protocol matches the sidebar_static_map setting" do
18
- it "renders the static map" do
19
- expect(rendered.css("#static-map")).to be_present
18
+ it "renders a locator map of where the record is" do
19
+ expect(rendered.css("ogm-locator#locator-map")).to be_present
20
+ end
21
+
22
+ it "points it at the same endpoint the item viewer reads its own metadata from" do
23
+ map = rendered.css("ogm-locator").first
24
+ expect(map["record-url"]).to eq Rails.application.routes.url_helpers.viewer_solr_document_path(document)
25
+ expect(map["theme"]).to be_nil
20
26
  end
21
27
  end
22
28
  end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe Geoblacklight::TruncatableMetadataFieldLayoutComponent, type: :component do
6
+ subject(:component) { described_class.new(field:) }
7
+
8
+ let(:field_config) { Blacklight::Configuration::Field.new(key: "dct_subject_sm") }
9
+ let(:field) { instance_double(Blacklight::FieldPresenter, key: "dct_subject_sm", field_config:) }
10
+
11
+ def render_field(component)
12
+ render_inline(component) do |layout|
13
+ layout.with_label { "Subject" }
14
+ layout.with_value(value: "Forests", index: 0)
15
+ layout.with_value(value: "Land use", index: 1)
16
+ end
17
+ end
18
+
19
+ it "wraps the label and the values in a row of their own" do
20
+ render_field(component)
21
+
22
+ expect(page).to have_css("div.truncate-field.row > dt.blacklight-dct_subject_sm", text: "Subject")
23
+ expect(page).to have_css("div.truncate-field.row > dd", count: 3) # two values plus the button slot
24
+ end
25
+
26
+ it "keeps each value in its own dd, in the columns the layout would have used" do
27
+ render_field(component)
28
+
29
+ expect(page).to have_css("dd.col-md-9.blacklight-dct_subject_sm", text: "Forests")
30
+ expect(page).to have_css("dd.offset-md-3.col-md-9.blacklight-dct_subject_sm", text: "Land use")
31
+ end
32
+
33
+ it "renders an empty dd for the initializer to put the button in" do
34
+ render_field(component)
35
+
36
+ # A <dl> may not hold a bare <button>, so the button cannot be a sibling of the values
37
+ expect(page).to have_css("div.truncate-field > dd.read-more-slot.offset-md-3.col-md-9")
38
+ expect(page.find("dd.read-more-slot").text).to be_empty
39
+ end
40
+
41
+ it "sets up the data attributes for the JS initializer" do
42
+ render_field(component)
43
+
44
+ expect(page).to have_css(
45
+ ".truncate-field[data-limit='5'][data-read-more-text='Read more'][data-close-text='Close']"
46
+ )
47
+ expect(page).to have_css(".truncate-field[data-button-label*='assistive technology']")
48
+ end
49
+
50
+ context "when the truncation parameters are given to the component" do
51
+ subject(:component) do
52
+ described_class.new(field:, limit: 2, read_more_text: "More", close_text: "Less")
53
+ end
54
+
55
+ it "uses them instead of the defaults" do
56
+ render_field(component)
57
+
58
+ expect(page).to have_css(
59
+ ".truncate-field[data-limit='2'][data-read-more-text='More'][data-close-text='Less']"
60
+ )
61
+ end
62
+ end
63
+
64
+ context "when the field configuration sets a limit" do
65
+ let(:field_config) { Blacklight::Configuration::Field.new(key: "dct_subject_sm", limit: 3) }
66
+
67
+ it "uses the configured limit" do
68
+ render_field(component)
69
+
70
+ expect(page).to have_css(".truncate-field[data-limit='3']")
71
+ end
72
+ end
73
+
74
+ context "when the layout is given different columns" do
75
+ subject(:component) { described_class.new(field:, label_class: "col-2", value_class: "col-10", offset_class: "offset-2") }
76
+
77
+ it "puts the button slot in the same columns as the values" do
78
+ render_field(component)
79
+
80
+ expect(page).to have_css("dd.read-more-slot.offset-2.col-10")
81
+ end
82
+ end
83
+ end