arclight 0.4.0 → 1.6.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 (227) hide show
  1. checksums.yaml +4 -4
  2. data/.eslintrc +11 -4
  3. data/.github/workflows/ruby.yml +37 -15
  4. data/.gitignore +1 -0
  5. data/.rspec +0 -1
  6. data/.rubocop.yml +498 -21
  7. data/.rubocop_todo.yml +69 -86
  8. data/.solr_wrapper +2 -1
  9. data/CONTRIBUTING.md +5 -5
  10. data/CONTRIBUTORS.md +1 -1
  11. data/Gemfile +15 -10
  12. data/README.md +20 -16
  13. data/app/assets/javascripts/arclight/arclight.js +4 -8
  14. data/app/assets/javascripts/arclight/oembed_controller.js +58 -0
  15. data/app/assets/javascripts/arclight/truncate_controller.js +27 -0
  16. data/app/assets/stylesheets/arclight/application.scss +2 -5
  17. data/app/assets/stylesheets/arclight/build.scss +4 -0
  18. data/app/assets/stylesheets/arclight/modules/hierarchy_and_online_contents.scss +108 -130
  19. data/app/assets/stylesheets/arclight/modules/icons.scss +19 -3
  20. data/app/assets/stylesheets/arclight/modules/layout.scss +129 -99
  21. data/app/assets/stylesheets/arclight/modules/mastheads.scss +23 -96
  22. data/app/assets/stylesheets/arclight/modules/repositories.scss +2 -2
  23. data/app/assets/stylesheets/arclight/modules/repository_card.scss +4 -48
  24. data/app/assets/stylesheets/arclight/modules/search_form.scss +9 -0
  25. data/app/assets/stylesheets/arclight/modules/search_results.scss +95 -45
  26. data/app/assets/stylesheets/arclight/modules/show_collection.scss +5 -32
  27. data/app/assets/stylesheets/arclight/modules/truncator.scss +58 -0
  28. data/app/assets/stylesheets/arclight/variables.scss +7 -4
  29. data/app/components/arclight/access_component.html.erb +14 -0
  30. data/app/components/arclight/access_component.rb +25 -0
  31. data/app/components/arclight/bookmark_component.html.erb +25 -0
  32. data/app/components/arclight/bookmark_component.rb +9 -0
  33. data/app/components/arclight/breadcrumb_component.rb +50 -0
  34. data/app/components/arclight/breadcrumbs_hierarchy_component.html.erb +34 -0
  35. data/app/components/arclight/breadcrumbs_hierarchy_component.rb +25 -0
  36. data/app/components/arclight/collection_context_component.html.erb +12 -0
  37. data/app/components/arclight/collection_context_component.rb +27 -0
  38. data/app/components/arclight/collection_info_component.html.erb +28 -0
  39. data/app/components/arclight/collection_info_component.rb +26 -0
  40. data/app/components/arclight/collection_sidebar_component.html.erb +15 -0
  41. data/app/components/arclight/collection_sidebar_component.rb +39 -0
  42. data/app/{views/catalog/_search_results_repository.html.erb → components/arclight/constraints_component.html.erb} +2 -1
  43. data/app/components/arclight/constraints_component.rb +17 -0
  44. data/app/components/arclight/document_collection_context_component.html.erb +29 -0
  45. data/app/components/arclight/document_collection_context_component.rb +28 -0
  46. data/app/components/arclight/document_collection_hierarchy_component.html.erb +50 -0
  47. data/app/components/arclight/document_collection_hierarchy_component.rb +62 -0
  48. data/app/components/arclight/document_component.html.erb +39 -0
  49. data/app/components/arclight/document_component.rb +49 -0
  50. data/app/components/arclight/document_components_hierarchy_component.html.erb +20 -0
  51. data/app/components/arclight/document_components_hierarchy_component.rb +34 -0
  52. data/app/components/arclight/document_download_component.html.erb +24 -0
  53. data/app/components/arclight/document_download_component.rb +71 -0
  54. data/app/components/arclight/embed_component.html.erb +10 -0
  55. data/app/components/arclight/embed_component.rb +43 -0
  56. data/app/components/arclight/expand_hierarchy_button_component.html.erb +5 -0
  57. data/app/components/arclight/expand_hierarchy_button_component.rb +16 -0
  58. data/app/components/arclight/group_component.html.erb +34 -0
  59. data/app/components/arclight/group_component.rb +23 -0
  60. data/app/components/arclight/header_component.html.erb +5 -0
  61. data/app/components/arclight/header_component.rb +10 -0
  62. data/app/components/arclight/index_metadata_field_component.html.erb +16 -0
  63. data/app/components/arclight/index_metadata_field_component.rb +20 -0
  64. data/app/components/arclight/masthead_component.html.erb +17 -0
  65. data/app/components/arclight/masthead_component.rb +10 -0
  66. data/app/components/arclight/metadata_section_component.html.erb +13 -0
  67. data/app/components/arclight/metadata_section_component.rb +22 -0
  68. data/app/components/arclight/oembed_viewer_component.html.erb +5 -0
  69. data/app/components/arclight/oembed_viewer_component.rb +16 -0
  70. data/app/components/arclight/online_content_filter_component.html.erb +15 -0
  71. data/app/components/arclight/online_content_filter_component.rb +17 -0
  72. data/app/components/arclight/online_status_indicator_component.rb +19 -0
  73. data/app/components/arclight/repository_breadcrumb_component.html.erb +10 -0
  74. data/app/components/arclight/repository_breadcrumb_component.rb +17 -0
  75. data/app/components/arclight/repository_location_component.html.erb +20 -0
  76. data/app/components/arclight/repository_location_component.rb +10 -0
  77. data/app/components/arclight/search_bar_component.html.erb +27 -0
  78. data/app/components/arclight/search_bar_component.rb +32 -0
  79. data/app/components/arclight/search_result_breadcrumbs_component.html.erb +6 -0
  80. data/app/components/arclight/search_result_breadcrumbs_component.rb +37 -0
  81. data/app/components/arclight/search_result_component.html.erb +20 -0
  82. data/app/components/arclight/search_result_component.rb +18 -0
  83. data/app/components/arclight/search_result_title_component.html.erb +15 -0
  84. data/app/components/arclight/search_result_title_component.rb +15 -0
  85. data/app/components/arclight/sidebar_component.html.erb +9 -0
  86. data/app/components/arclight/sidebar_component.rb +19 -0
  87. data/app/components/arclight/upper_metadata_layout_component.rb +10 -0
  88. data/app/components/blacklight/icons/bookmark_component.rb +12 -0
  89. data/app/components/blacklight/icons/collection_component.rb +14 -0
  90. data/app/components/blacklight/icons/compact_component.rb +12 -0
  91. data/app/components/blacklight/icons/container_component.rb +14 -0
  92. data/app/components/blacklight/icons/ead_component.rb +12 -0
  93. data/app/components/blacklight/icons/file_component.rb +14 -0
  94. data/app/components/blacklight/icons/folder_component.rb +12 -0
  95. data/app/components/blacklight/icons/online_component.rb +15 -0
  96. data/app/components/blacklight/icons/pdf_component.rb +12 -0
  97. data/app/components/blacklight/icons/repository_component.rb +12 -0
  98. data/app/controllers/arclight/repositories_controller.rb +4 -4
  99. data/app/{controllers/concerns → helpers}/arclight/ead_format_helpers.rb +91 -7
  100. data/app/helpers/arclight/field_config_helpers.rb +26 -0
  101. data/app/helpers/arclight_helper.rb +24 -251
  102. data/app/models/arclight/document_downloads.rb +12 -15
  103. data/app/models/arclight/parent.rb +6 -8
  104. data/app/models/arclight/parents.rb +7 -4
  105. data/app/models/arclight/requests/aeon_external_request.rb +1 -1
  106. data/app/models/arclight/requests/aeon_web_ead.rb +8 -3
  107. data/app/models/arclight/requests/google_form.rb +8 -3
  108. data/app/models/concerns/arclight/catalog.rb +25 -15
  109. data/app/models/concerns/arclight/search_behavior.rb +12 -26
  110. data/app/models/concerns/arclight/solr_document.rb +80 -73
  111. data/app/presenters/arclight/show_presenter.rb +34 -7
  112. data/app/views/arclight/_requests.html.erb +2 -2
  113. data/app/views/arclight/repositories/_repository.html.erb +21 -40
  114. data/app/views/arclight/repositories/index.html.erb +3 -1
  115. data/app/views/arclight/repositories/show.html.erb +4 -6
  116. data/app/views/arclight/requests/_aeon_external_request_endpoint.html.erb +4 -5
  117. data/app/views/arclight/requests/_aeon_web_ead.html.erb +3 -4
  118. data/app/views/arclight/requests/_google_form.html.erb +4 -6
  119. data/app/views/catalog/_document_list.html.erb +8 -0
  120. data/app/views/catalog/_group.html.erb +2 -19
  121. data/app/views/catalog/_group_toggle.html.erb +1 -1
  122. data/app/views/catalog/_search_results_header.html.erb +3 -0
  123. data/app/views/catalog/hierarchy.html.erb +19 -0
  124. data/app/views/catalog/index.html.erb +16 -7
  125. data/app/views/shared/_breadcrumbs.html.erb +2 -14
  126. data/app/views/shared/_main_menu_links.html.erb +1 -1
  127. data/arclight.gemspec +16 -14
  128. data/config/breadcrumbs.rb +24 -0
  129. data/config/i18n-tasks.yml +9 -8
  130. data/config/importmap.rb +3 -0
  131. data/config/locales/arclight.en.yml +31 -30
  132. data/config/routes.rb +1 -1
  133. data/docker-compose.yml +16 -0
  134. data/lib/arclight/digital_object.rb +2 -1
  135. data/lib/arclight/engine.rb +18 -37
  136. data/lib/arclight/exceptions.rb +1 -0
  137. data/lib/arclight/hash_absolute_xpath.rb +2 -1
  138. data/lib/arclight/normalized_date.rb +5 -10
  139. data/lib/arclight/normalized_id.rb +6 -2
  140. data/lib/arclight/normalized_title.rb +2 -0
  141. data/lib/arclight/repository.rb +46 -57
  142. data/lib/arclight/routes/hierarchy.rb +19 -0
  143. data/lib/arclight/routes.rb +8 -0
  144. data/lib/arclight/traject/ead2_component_config.rb +335 -0
  145. data/lib/arclight/traject/ead2_config.rb +120 -299
  146. data/lib/arclight/version.rb +1 -1
  147. data/lib/arclight/year_range.rb +4 -3
  148. data/lib/arclight.rb +6 -1
  149. data/lib/generators/arclight/install_generator.rb +94 -21
  150. data/lib/generators/arclight/templates/arclight.scss +6 -3
  151. data/lib/generators/arclight/templates/catalog_controller.rb +193 -165
  152. data/lib/generators/arclight/templates/config/locales/arclight.en.yml +61 -0
  153. data/lib/generators/arclight/templates/config/repositories.yml +22 -29
  154. data/lib/tasks/index.rake +14 -17
  155. data/package.json +13 -14
  156. data/solr/conf/schema.xml +49 -39
  157. data/solr/conf/solrconfig.xml +78 -58
  158. data/tasks/arclight.rake +17 -9
  159. data/template.rb +6 -7
  160. metadata +149 -123
  161. data/.babelrc +0 -3
  162. data/app/assets/javascripts/arclight/collection_navigation.js +0 -100
  163. data/app/assets/javascripts/arclight/collection_scrollspy.js +0 -6
  164. data/app/assets/javascripts/arclight/context_navigation.js +0 -351
  165. data/app/assets/javascripts/arclight/oembed_viewer.js +0 -46
  166. data/app/assets/javascripts/arclight/truncator.js.erb +0 -29
  167. data/app/assets/stylesheets/arclight/bootstrap_overrides.scss +0 -26
  168. data/app/assets/stylesheets/arclight/modules/context_navigation.scss +0 -75
  169. data/app/controllers/concerns/arclight/field_config_helpers.rb +0 -102
  170. data/app/factories/blacklight_field_configuration_factory.rb +0 -30
  171. data/app/views/arclight/repositories/_in_person_repository.html.erb +0 -19
  172. data/app/views/arclight/repositories/_repository_contact.html.erb +0 -9
  173. data/app/views/arclight/viewers/_oembed.html.erb +0 -8
  174. data/app/views/catalog/_access_contents.html.erb +0 -15
  175. data/app/views/catalog/_arclight_abstract_or_scope.html.erb +0 -5
  176. data/app/views/catalog/_arclight_bookmark_control.html.erb +0 -38
  177. data/app/views/catalog/_arclight_document_header_icon.html.erb +0 -1
  178. data/app/views/catalog/_arclight_document_index_header.html.erb +0 -13
  179. data/app/views/catalog/_arclight_document_index_header_hierarchy_default.html.erb +0 -0
  180. data/app/views/catalog/_arclight_document_index_header_online_contents_default.html.erb +0 -0
  181. data/app/views/catalog/_arclight_index_compact_default.html.erb +0 -22
  182. data/app/views/catalog/_arclight_index_default.html.erb +0 -45
  183. data/app/views/catalog/_arclight_index_group_document_compact_default.html.erb +0 -19
  184. data/app/views/catalog/_arclight_index_group_document_default.html.erb +0 -18
  185. data/app/views/catalog/_arclight_online_content_indicator.html.erb +0 -3
  186. data/app/views/catalog/_arclight_rangelimit.html.erb +0 -24
  187. data/app/views/catalog/_arclight_viewer_default.html.erb +0 -1
  188. data/app/views/catalog/_collection_contents.html.erb +0 -4
  189. data/app/views/catalog/_collection_context.html.erb +0 -15
  190. data/app/views/catalog/_collection_context_nav.html.erb +0 -12
  191. data/app/views/catalog/_collection_online_contents.html.erb +0 -17
  192. data/app/views/catalog/_component_context.html.erb +0 -5
  193. data/app/views/catalog/_containers.html.erb +0 -3
  194. data/app/views/catalog/_context_card.html.erb +0 -27
  195. data/app/views/catalog/_context_sidebar.html.erb +0 -8
  196. data/app/views/catalog/_custom_metadata.html.erb +0 -16
  197. data/app/views/catalog/_document_downloads.html.erb +0 -14
  198. data/app/views/catalog/_group_header_compact_default.html.erb +0 -15
  199. data/app/views/catalog/_group_header_default.html.erb +0 -20
  200. data/app/views/catalog/_home.html.erb +0 -1
  201. data/app/views/catalog/_index_breadcrumb_default.html.erb +0 -6
  202. data/app/views/catalog/_index_collection_context_default.html.erb +0 -53
  203. data/app/views/catalog/_index_default.html.erb +0 -17
  204. data/app/views/catalog/_index_header.html.erb +0 -7
  205. data/app/views/catalog/_index_header_online_contents_default.html.erb +0 -1
  206. data/app/views/catalog/_index_online_contents_default.html.erb +0 -6
  207. data/app/views/catalog/_online_content_label.html.erb +0 -5
  208. data/app/views/catalog/_search_form.html.erb +0 -34
  209. data/app/views/catalog/_search_results.html.erb +0 -28
  210. data/app/views/catalog/_show_actions_box_default.html.erb +0 -27
  211. data/app/views/catalog/_show_breadcrumbs_default.html.erb +0 -6
  212. data/app/views/catalog/_show_collection.html.erb +0 -66
  213. data/app/views/catalog/_show_default.html.erb +0 -70
  214. data/app/views/catalog/_show_upper_metadata_collection.html.erb +0 -1
  215. data/app/views/catalog/_show_upper_metadata_default.html.erb +0 -14
  216. data/app/views/catalog/_sort_and_per_page.html.erb +0 -8
  217. data/app/views/catalog/_within_collection_dropdown.html.erb +0 -26
  218. data/app/views/layouts/catalog_result.html.erb +0 -7
  219. data/app/views/shared/_context_sidebar.html.erb +0 -8
  220. data/app/views/shared/_header_navbar.html.erb +0 -61
  221. data/app/views/shared/_show_breadcrumbs.html.erb +0 -27
  222. data/lib/arclight/viewer.rb +0 -45
  223. data/lib/arclight/viewers/oembed.rb +0 -57
  224. data/solr/conf/scripts.conf +0 -24
  225. data/vendor/assets/javascripts/responsiveTruncator.js +0 -69
  226. data/vendor/assets/javascripts/stickyfill.js +0 -480
  227. /data/app/assets/images/{blacklight → arclight}/logo.png +0 -0
@@ -5,8 +5,8 @@ require 'traject'
5
5
  require 'traject/nokogiri_reader'
6
6
  require 'traject_plus'
7
7
  require 'traject_plus/macros'
8
- require 'arclight/exceptions'
9
8
  require 'arclight/level_label'
9
+ require 'arclight/normalized_id'
10
10
  require 'arclight/normalized_date'
11
11
  require 'arclight/normalized_title'
12
12
  require 'active_model/conversion' ## Needed for Arclight::Repository
@@ -14,7 +14,6 @@ require 'active_support/core_ext/array/wrap'
14
14
  require 'arclight/digital_object'
15
15
  require 'arclight/year_range'
16
16
  require 'arclight/repository'
17
- require 'arclight/missing_id_strategy'
18
17
  require 'arclight/traject/nokogiri_namespaceless_reader'
19
18
 
20
19
  # rubocop:disable Style/MixinUsage
@@ -50,12 +49,17 @@ DID_SEARCHABLE_NOTES_FIELDS = %w[
50
49
  abstract
51
50
  materialspec
52
51
  physloc
52
+ note
53
53
  ].freeze
54
54
 
55
55
  settings do
56
+ provide 'component_traject_config', File.join(__dir__, 'ead2_component_config.rb')
57
+ provide 'id_normalizer', 'Arclight::NormalizedId'
58
+ provide 'date_normalizer', 'Arclight::NormalizedDate'
59
+ provide 'title_normalizer', 'Arclight::NormalizedTitle'
56
60
  provide 'reader_class_name', 'Arclight::Traject::NokogiriNamespacelessReader'
57
61
  provide 'solr_writer.commit_on_close', 'true'
58
- provide 'repository', ENV['REPOSITORY_ID']
62
+ provide 'repository', ENV.fetch('REPOSITORY_ID', nil)
59
63
  provide 'logger', Logger.new($stderr)
60
64
  end
61
65
 
@@ -69,12 +73,21 @@ end
69
73
 
70
74
  # ==================
71
75
  # Top level document
76
+ #
77
+ # NOTE: All fields should be stored in Solr
72
78
  # ==================
73
79
 
74
- to_field 'id', extract_xpath('/ead/eadheader/eadid'), strip, gsub('.', '-')
75
- to_field 'title_filing_si', extract_xpath('/ead/eadheader/filedesc/titlestmt/titleproper[@type="filing"]')
80
+ to_field 'id' do |record, accumulator|
81
+ id = record.at_xpath('/ead/eadheader/eadid')&.text
82
+ unitid = record.at_xpath('/ead/archdesc/did/unitid')&.text
83
+ title = record.at_xpath('/ead/archdesc/did/unittitle')&.text
84
+ repository = settings['repository']
85
+ accumulator << settings['id_normalizer'].constantize.new(id, unitid: unitid, title: title, repository: repository).to_s
86
+ end
87
+
88
+ to_field 'title_filing_ssi', extract_xpath('/ead/eadheader/filedesc/titlestmt/titleproper[@type="filing"]')
76
89
  to_field 'title_ssm', extract_xpath('/ead/archdesc/did/unittitle')
77
- to_field 'title_teim', extract_xpath('/ead/archdesc/did/unittitle')
90
+ to_field 'title_tesim', extract_xpath('/ead/archdesc/did/unittitle')
78
91
  to_field 'ead_ssi', extract_xpath('/ead/eadheader/eadid')
79
92
 
80
93
  to_field 'unitdate_ssm', extract_xpath('/ead/archdesc/did/unitdate')
@@ -88,7 +101,7 @@ to_field 'level_ssm' do |_record, accumulator|
88
101
  end
89
102
 
90
103
  # Keep the original top-level archdesc/@level for Level facet in addition to 'Collection'
91
- to_field 'level_sim' do |record, accumulator|
104
+ to_field 'level_ssim' do |record, accumulator|
92
105
  level = record.at_xpath('/ead/archdesc').attribute('level')&.value
93
106
  other_level = record.at_xpath('/ead/archdesc').attribute('otherlevel')&.value
94
107
 
@@ -97,37 +110,27 @@ to_field 'level_sim' do |record, accumulator|
97
110
  end
98
111
 
99
112
  to_field 'unitid_ssm', extract_xpath('/ead/archdesc/did/unitid')
100
- to_field 'unitid_teim', extract_xpath('/ead/archdesc/did/unitid')
101
- to_field 'collection_unitid_ssm', extract_xpath('/ead/archdesc/did/unitid')
102
-
103
- to_field 'normalized_title_ssm' do |_record, accumulator, context|
104
- dates = Arclight::NormalizedDate.new(
105
- context.output_hash['unitdate_inclusive_ssm'],
106
- context.output_hash['unitdate_bulk_ssim'],
107
- context.output_hash['unitdate_other_ssim']
108
- ).to_s
109
- title = context.output_hash['title_ssm'].first
110
- accumulator << Arclight::NormalizedTitle.new(title, dates).to_s
111
- end
113
+ to_field 'unitid_tesim', extract_xpath('/ead/archdesc/did/unitid')
112
114
 
113
115
  to_field 'normalized_date_ssm' do |_record, accumulator, context|
114
- accumulator << Arclight::NormalizedDate.new(
116
+ accumulator << settings['date_normalizer'].constantize.new(
115
117
  context.output_hash['unitdate_inclusive_ssm'],
116
118
  context.output_hash['unitdate_bulk_ssim'],
117
119
  context.output_hash['unitdate_other_ssim']
118
120
  ).to_s
119
121
  end
120
122
 
121
- to_field 'collection_ssm' do |_record, accumulator, context|
122
- accumulator.concat context.output_hash.fetch('normalized_title_ssm', [])
123
- end
124
- to_field 'collection_sim' do |_record, accumulator, context|
125
- accumulator.concat context.output_hash.fetch('normalized_title_ssm', [])
123
+ to_field 'normalized_title_ssm' do |_record, accumulator, context|
124
+ title = context.output_hash['title_ssm']&.first
125
+ date = context.output_hash['normalized_date_ssm']&.first
126
+ accumulator << settings['title_normalizer'].constantize.new(title, date).to_s
126
127
  end
127
- to_field 'collection_ssi' do |_record, accumulator, context|
128
+
129
+ to_field 'collection_title_tesim' do |_record, accumulator, context|
128
130
  accumulator.concat context.output_hash.fetch('normalized_title_ssm', [])
129
131
  end
130
- to_field 'collection_title_tesim' do |_record, accumulator, context|
132
+
133
+ to_field 'collection_ssim' do |_record, accumulator, context|
131
134
  accumulator.concat context.output_hash.fetch('normalized_title_ssm', [])
132
135
  end
133
136
 
@@ -135,39 +138,30 @@ to_field 'repository_ssm' do |_record, accumulator, context|
135
138
  accumulator << context.clipboard[:repository]
136
139
  end
137
140
 
138
- to_field 'repository_sim' do |_record, accumulator, context|
141
+ to_field 'repository_ssim' do |_record, accumulator, context|
139
142
  accumulator << context.clipboard[:repository]
140
143
  end
141
144
 
142
145
  to_field 'geogname_ssm', extract_xpath('/ead/archdesc/controlaccess/geogname')
143
- to_field 'geogname_sim', extract_xpath('/ead/archdesc/controlaccess/geogname')
146
+ to_field 'geogname_ssim', extract_xpath('/ead/archdesc/controlaccess/geogname')
144
147
 
145
148
  to_field 'creator_ssm', extract_xpath('/ead/archdesc/did/origination')
146
- to_field 'creator_sim', extract_xpath('/ead/archdesc/did/origination')
147
149
  to_field 'creator_ssim', extract_xpath('/ead/archdesc/did/origination')
148
150
  to_field 'creator_sort' do |record, accumulator|
149
151
  accumulator << record.xpath('/ead/archdesc/did/origination').map { |c| c.text.strip }.join(', ')
150
152
  end
151
153
 
152
- to_field 'creator_persname_ssm', extract_xpath('/ead/archdesc/did/origination/persname')
153
154
  to_field 'creator_persname_ssim', extract_xpath('/ead/archdesc/did/origination/persname')
154
- to_field 'creator_corpname_ssm', extract_xpath('/ead/archdesc/did/origination/corpname')
155
- to_field 'creator_corpname_sim', extract_xpath('/ead/archdesc/did/origination/corpname')
156
155
  to_field 'creator_corpname_ssim', extract_xpath('/ead/archdesc/did/origination/corpname')
157
- to_field 'creator_famname_ssm', extract_xpath('/ead/archdesc/did/origination/famname')
158
156
  to_field 'creator_famname_ssim', extract_xpath('/ead/archdesc/did/origination/famname')
159
157
 
160
- to_field 'persname_sim', extract_xpath('//persname')
161
-
162
158
  to_field 'creators_ssim' do |_record, accumulator, context|
163
- accumulator.concat context.output_hash['creator_persname_ssm'] if context.output_hash['creator_persname_ssm']
164
- accumulator.concat context.output_hash['creator_corpname_ssm'] if context.output_hash['creator_corpname_ssm']
165
- accumulator.concat context.output_hash['creator_famname_ssm'] if context.output_hash['creator_famname_ssm']
159
+ accumulator.concat context.output_hash['creator_persname_ssim'] if context.output_hash['creator_persname_ssim']
160
+ accumulator.concat context.output_hash['creator_corpname_ssim'] if context.output_hash['creator_corpname_ssim']
161
+ accumulator.concat context.output_hash['creator_famname_ssim'] if context.output_hash['creator_famname_ssim']
166
162
  end
167
163
 
168
- to_field 'places_sim', extract_xpath('/ead/archdesc/controlaccess/geogname')
169
164
  to_field 'places_ssim', extract_xpath('/ead/archdesc/controlaccess/geogname')
170
- to_field 'places_ssm', extract_xpath('/ead/archdesc/controlaccess/geogname')
171
165
 
172
166
  to_field 'access_terms_ssm', extract_xpath('/ead/archdesc/userestrict/*[local-name()!="head"]')
173
167
 
@@ -199,12 +193,41 @@ to_field 'digital_objects_ssm', extract_xpath('/ead/archdesc/did/dao|/ead/archde
199
193
  end
200
194
  end
201
195
 
202
- to_field 'extent_ssm', extract_xpath('/ead/archdesc/did/physdesc/extent')
203
- to_field 'extent_teim', extract_xpath('/ead/archdesc/did/physdesc/extent')
204
- to_field 'genreform_sim', extract_xpath('/ead/archdesc/controlaccess/genreform')
205
- to_field 'genreform_ssm', extract_xpath('/ead/archdesc/controlaccess/genreform')
196
+ # This accumulates direct text from a physdesc, ignoring child elements handled elsewhere
197
+ to_field 'physdesc_tesim', extract_xpath('/ead/archdesc/did/physdesc', to_text: false) do |_record, accumulator|
198
+ accumulator.map! do |element|
199
+ physdesc = []
200
+ element.children.map do |child|
201
+ next if child.instance_of?(Nokogiri::XML::Element)
202
+
203
+ physdesc << child.text&.strip unless child.text&.strip&.empty?
204
+ end.flatten
205
+ physdesc.join(' ') unless physdesc.empty?
206
+ end
207
+ end
208
+
209
+ to_field 'extent_ssm' do |record, accumulator|
210
+ physdescs = record.xpath('/ead/archdesc/did/physdesc')
211
+ extents_per_physdesc = physdescs.map do |physdesc|
212
+ extents = physdesc.xpath('./extent').map { |e| e.text.strip }
213
+ # Join extents within the same physdesc with an empty string
214
+ extents.join(' ') unless extents.empty?
215
+ end
216
+
217
+ # Add each physdesc separately to the accumulator
218
+ accumulator.concat(extents_per_physdesc)
219
+ end
220
+
221
+ to_field 'extent_tesim' do |_record, accumulator, context|
222
+ accumulator.concat context.output_hash['extent_ssm'] || []
223
+ end
206
224
 
207
- to_field 'date_range_sim', extract_xpath('/ead/archdesc/did/unitdate/@normal', to_text: false) do |_record, accumulator|
225
+ to_field 'physfacet_tesim', extract_xpath('/ead/archdesc/did/physdesc/physfacet')
226
+ to_field 'dimensions_tesim', extract_xpath('/ead/archdesc/did/physdesc/dimensions')
227
+
228
+ to_field 'genreform_ssim', extract_xpath('/ead/archdesc/controlaccess/genreform')
229
+
230
+ to_field 'date_range_isim', extract_xpath('/ead/archdesc/did/unitdate/@normal', to_text: false) do |_record, accumulator|
208
231
  range = Arclight::YearRange.new
209
232
  next range.years if accumulator.blank?
210
233
 
@@ -213,283 +236,81 @@ to_field 'date_range_sim', extract_xpath('/ead/archdesc/did/unitdate/@normal', t
213
236
  accumulator.replace range.years
214
237
  end
215
238
 
239
+ to_field 'indexes_html_tesm', extract_xpath('/ead/archdesc/index', to_text: false)
240
+ to_field 'indexes_tesim', extract_xpath('/ead/archdesc/index')
241
+
216
242
  SEARCHABLE_NOTES_FIELDS.map do |selector|
217
- to_field "#{selector}_ssm", extract_xpath("/ead/archdesc/#{selector}/*[local-name()!='head']", to_text: false)
243
+ to_field "#{selector}_html_tesm", extract_xpath("/ead/archdesc/#{selector}/*[local-name()!='head']", to_text: false) do |_record, accumulator|
244
+ accumulator.map!(&:to_html)
245
+ end
218
246
  to_field "#{selector}_heading_ssm", extract_xpath("/ead/archdesc/#{selector}/head") unless selector == 'prefercite'
219
- to_field "#{selector}_teim", extract_xpath("/ead/archdesc/#{selector}/*[local-name()!='head']")
247
+ to_field "#{selector}_tesim", extract_xpath("/ead/archdesc/#{selector}/*[local-name()!='head']")
220
248
  end
221
249
 
222
250
  DID_SEARCHABLE_NOTES_FIELDS.map do |selector|
223
- to_field "#{selector}_ssm", extract_xpath("/ead/archdesc/did/#{selector}", to_text: false)
251
+ to_field "#{selector}_html_tesm", extract_xpath("/ead/archdesc/did/#{selector}", to_text: false)
252
+ to_field "#{selector}_tesim", extract_xpath("/ead/archdesc/did/#{selector}")
224
253
  end
225
254
 
226
255
  NAME_ELEMENTS.map do |selector|
227
256
  to_field 'names_coll_ssim', extract_xpath("/ead/archdesc/controlaccess/#{selector}")
228
- to_field 'names_ssim', extract_xpath("//#{selector}")
229
- to_field "#{selector}_ssm", extract_xpath("//#{selector}")
257
+ to_field 'names_ssim', extract_xpath("//#{selector}"), unique
258
+ to_field "#{selector}_ssim", extract_xpath("//#{selector}"), unique
230
259
  end
231
260
 
232
- to_field 'corpname_sim', extract_xpath('//corpname')
233
-
234
- to_field 'language_sim', extract_xpath('/ead/archdesc/did/langmaterial')
235
- to_field 'language_ssm', extract_xpath('/ead/archdesc/did/langmaterial')
261
+ to_field 'language_ssim', extract_xpath('/ead/archdesc/did/langmaterial')
236
262
 
237
263
  to_field 'descrules_ssm', extract_xpath('/ead/eadheader/profiledesc/descrules')
238
264
 
239
- # =============================
240
- # Each component child document
241
- # <c> <c01> <c12>
242
- # =============================
243
-
244
- compose 'components', ->(record, accumulator, _context) { accumulator.concat record.xpath('//*[is_component(.)]', NokogiriXpathExtensions.new) } do
245
- to_field 'ref_ssi' do |record, accumulator, context|
246
- accumulator << if record.attribute('id').blank?
247
- strategy = Arclight::MissingIdStrategy.selected
248
- hexdigest = strategy.new(record).to_hexdigest
249
- parent_id = context.clipboard[:parent].output_hash['id'].first
250
- logger.warn('MISSING ID WARNING') do
251
- [
252
- "A component in #{parent_id} did not have an ID so one was minted using the #{strategy} strategy.",
253
- "The ID of this document will be #{parent_id}#{hexdigest}."
254
- ].join(' ')
255
- end
256
- record['id'] = hexdigest
257
- hexdigest
258
- else
259
- record.attribute('id')&.value&.strip&.gsub('.', '-')
260
- end
261
- end
262
- to_field 'ref_ssm' do |_record, accumulator, context|
263
- accumulator.concat context.output_hash['ref_ssi']
264
- end
265
-
266
- to_field 'id' do |_record, accumulator, context|
267
- accumulator << [
268
- context.clipboard[:parent].output_hash['id'],
269
- context.output_hash['ref_ssi']
270
- ].join('')
271
- end
272
-
273
- to_field 'ead_ssi' do |_record, accumulator, context|
274
- accumulator << context.clipboard[:parent].output_hash['ead_ssi'].first
275
- end
276
-
277
- to_field 'title_filing_si', extract_xpath('./did/unittitle'), first_only
278
- to_field 'title_ssm', extract_xpath('./did/unittitle')
279
- to_field 'title_teim', extract_xpath('./did/unittitle')
280
-
281
- to_field 'unitdate_bulk_ssim', extract_xpath('./did/unitdate[@type="bulk"]')
282
- to_field 'unitdate_inclusive_ssm', extract_xpath('./did/unitdate[@type="inclusive"]')
283
- to_field 'unitdate_other_ssim', extract_xpath('./did/unitdate[not(@type)]')
284
-
285
- to_field 'normalized_title_ssm' do |_record, accumulator, context|
286
- dates = Arclight::NormalizedDate.new(
287
- context.output_hash['unitdate_inclusive_ssm'],
288
- context.output_hash['unitdate_bulk_ssim'],
289
- context.output_hash['unitdate_other_ssim']
290
- ).to_s
291
- title = context.output_hash['title_ssm']&.first
292
- accumulator << Arclight::NormalizedTitle.new(title, dates).to_s
293
- end
294
-
295
- to_field 'normalized_date_ssm' do |_record, accumulator, context|
296
- accumulator << Arclight::NormalizedDate.new(
297
- context.output_hash['unitdate_inclusive_ssm'],
298
- context.output_hash['unitdate_bulk_ssim'],
299
- context.output_hash['unitdate_other_ssim']
300
- ).to_s
301
- end
302
-
303
- to_field 'component_level_isim' do |record, accumulator|
304
- accumulator << 1 + NokogiriXpathExtensions.new.is_component(record.ancestors).count
305
- end
306
-
307
- to_field 'parent_ssim' do |record, accumulator, context|
308
- accumulator << context.clipboard[:parent].output_hash['id'].first
309
- accumulator.concat NokogiriXpathExtensions.new.is_component(record.ancestors).reverse.map { |n| n.attribute('id')&.value }
310
- end
311
-
312
- to_field 'parent_ssi' do |_record, accumulator, context|
313
- accumulator << context.output_hash['parent_ssim'].last
314
- end
315
-
316
- to_field 'parent_unittitles_ssm' do |_rec, accumulator, context|
317
- # top level document
318
- accumulator.concat context.clipboard[:parent].output_hash['normalized_title_ssm']
319
- parent_ssim = context.output_hash['parent_ssim']
320
- components = context.clipboard[:parent].output_hash['components']
321
-
322
- # other components
323
- if parent_ssim && components
324
- ancestors = parent_ssim.drop(1).map { |x| [x] }
325
- accumulator.concat components.select { |c| ancestors.include? c['ref_ssi'] }.flat_map { |c| c['normalized_title_ssm'] }
326
- end
327
- end
328
-
329
- to_field 'parent_unittitles_teim' do |_record, accumulator, context|
330
- accumulator.concat context.output_hash['parent_unittitles_ssm']
331
- end
332
-
333
- to_field 'parent_levels_ssm' do |_record, accumulator, context|
334
- ## Top level document
335
- accumulator.concat context.clipboard[:parent].output_hash['level_ssm']
336
- ## Other components
337
- context.output_hash['parent_ssim']&.drop(1)&.each do |id|
338
- accumulator.concat Array
339
- .wrap(context.clipboard[:parent].output_hash['components'])
340
- .select { |c| c['ref_ssi'] == [id] }.map { |c| c['level_ssm'] }.flatten
341
- end
342
- end
343
-
344
- to_field 'unitid_ssm', extract_xpath('./did/unitid')
345
- to_field 'collection_unitid_ssm' do |_record, accumulator, context|
346
- accumulator.concat Array.wrap(context.clipboard[:parent].output_hash['unitid_ssm'])
347
- end
348
- to_field 'repository_ssm' do |_record, accumulator, context|
349
- accumulator << context.clipboard[:parent].clipboard[:repository]
350
- end
351
- to_field 'repository_sim' do |_record, accumulator, context|
352
- accumulator << context.clipboard[:parent].clipboard[:repository]
353
- end
354
- to_field 'collection_ssm' do |_record, accumulator, context|
355
- accumulator.concat context.clipboard[:parent].output_hash['normalized_title_ssm']
356
- end
357
- to_field 'collection_sim' do |_record, accumulator, context|
358
- accumulator.concat context.clipboard[:parent].output_hash['normalized_title_ssm']
359
- end
360
- to_field 'collection_ssi' do |_record, accumulator, context|
361
- accumulator.concat context.clipboard[:parent].output_hash['normalized_title_ssm']
362
- end
363
-
364
- to_field 'extent_ssm', extract_xpath('./did/physdesc/extent')
365
- to_field 'extent_teim', extract_xpath('./did/physdesc/extent')
366
-
367
- to_field 'creator_ssm', extract_xpath('./did/origination')
368
- to_field 'creator_ssim', extract_xpath('./did/origination')
369
- to_field 'creators_ssim', extract_xpath('./did/origination')
370
- to_field 'creator_sort' do |record, accumulator|
371
- accumulator << record.xpath('./did/origination').map(&:text).join(', ')
372
- end
373
- to_field 'collection_creator_ssm' do |_record, accumulator, context|
374
- accumulator.concat Array.wrap(context.clipboard[:parent].output_hash['creator_ssm'])
375
- end
376
- to_field 'has_online_content_ssim', extract_xpath('.//dao') do |_record, accumulator|
377
- accumulator.replace([accumulator.any?])
378
- end
379
- to_field 'child_component_count_isim' do |record, accumulator|
380
- accumulator << NokogiriXpathExtensions.new.is_component(record.children).count
381
- end
382
-
383
- to_field 'ref_ssm' do |record, accumulator|
384
- accumulator << record.attribute('id')
385
- end
386
-
387
- to_field 'level_ssm' do |record, accumulator|
388
- level = record.attribute('level')&.value
389
- other_level = record.attribute('otherlevel')&.value
390
- accumulator << Arclight::LevelLabel.new(level, other_level).to_s
391
- end
265
+ # count all descendant components from the top-level
266
+ to_field 'total_component_count_is', first_only do |record, accumulator|
267
+ accumulator << record.xpath('//c|//c01|//c02|//c03|//c04|//c05|//c06|//c07|//c08|//c09|//c10|//c11|//c12').count
268
+ end
392
269
 
393
- to_field 'level_sim' do |_record, accumulator, context|
394
- next unless context.output_hash['level_ssm']
270
+ # count all digital objects from the top-level
271
+ to_field 'online_item_count_is', first_only do |record, accumulator|
272
+ accumulator << record.xpath('//dao').count
273
+ end
395
274
 
396
- accumulator.concat context.output_hash['level_ssm']&.map(&:capitalize)
397
- end
275
+ to_field 'component_level_isim' do |_record, accumulator, _context|
276
+ accumulator << 0
277
+ end
398
278
 
399
- to_field 'sort_ii' do |_record, accumulator, context|
400
- accumulator.replace([context.position])
401
- end
279
+ to_field 'sort_isi' do |_record, accumulator, _context|
280
+ accumulator << 0
281
+ end
402
282
 
403
- # Get the <accessrestrict> from the closest ancestor that has one (includes top-level)
404
- to_field 'parent_access_restrict_ssm' do |record, accumulator|
405
- accumulator.concat Array
406
- .wrap(record.xpath('(./ancestor::*/accessrestrict)[last()]/*[local-name()!="head"]')
407
- .map(&:text))
408
- end
283
+ # =============================
284
+ # Each component child document
285
+ # <c> <c01> <c12>
286
+ # =============================
409
287
 
410
- # Get the <userestrict> from self OR the closest ancestor that has one (includes top-level)
411
- to_field 'parent_access_terms_ssm' do |record, accumulator|
412
- accumulator.concat Array
413
- .wrap(record.xpath('(./ancestor-or-self::*/userestrict)[last()]/*[local-name()!="head"]')
414
- .map(&:text))
415
- end
288
+ to_field 'components' do |record, accumulator, context|
289
+ child_components = record.xpath("/ead/archdesc/dsc/c|#{('/ead/archdesc/dsc/c01'..'/ead/archdesc/dsc/c12').to_a.join('|')}")
290
+ next unless child_components.any?
416
291
 
417
- to_field 'digital_objects_ssm', extract_xpath('./dao|./did/dao', to_text: false) do |_record, accumulator|
418
- accumulator.map! do |dao|
419
- label = dao.attributes['title']&.value ||
420
- dao.xpath('daodesc/p')&.text
421
- href = (dao.attributes['href'] || dao.attributes['xlink:href'])&.value
422
- Arclight::DigitalObject.new(label: label, href: href).to_json
292
+ counter = Class.new do
293
+ def increment
294
+ @counter ||= 0
295
+ @counter += 1
423
296
  end
424
- end
425
-
426
- to_field 'date_range_sim', extract_xpath('./did/unitdate/@normal', to_text: false) do |_record, accumulator|
427
- range = Arclight::YearRange.new
428
- next range.years if accumulator.blank?
429
-
430
- ranges = accumulator.map(&:to_s)
431
- range << range.parse_ranges(ranges)
432
- accumulator.replace range.years
433
- end
434
-
435
- NAME_ELEMENTS.map do |selector|
436
- to_field 'names_ssim', extract_xpath("./controlaccess/#{selector}")
437
- to_field "#{selector}_ssm", extract_xpath(".//#{selector}")
438
- end
439
-
440
- to_field 'geogname_sim', extract_xpath('./controlaccess/geogname')
441
- to_field 'geogname_ssm', extract_xpath('./controlaccess/geogname')
442
- to_field 'places_ssim', extract_xpath('./controlaccess/geogname')
443
-
444
- to_field 'access_subjects_ssim', extract_xpath('./controlaccess', to_text: false) do |_record, accumulator|
445
- accumulator.map! do |element|
446
- %w[subject function occupation genreform].map do |selector|
447
- element.xpath(".//#{selector}").map(&:text)
448
- end
449
- end.flatten!
450
- end
451
-
452
- to_field 'access_subjects_ssm' do |_record, accumulator, context|
453
- accumulator.concat(context.output_hash.fetch('access_subjects_ssim', []))
454
- end
455
-
456
- to_field 'acqinfo_ssim', extract_xpath('/ead/archdesc/acqinfo/*[local-name()!="head"]')
457
- to_field 'acqinfo_ssim', extract_xpath('/ead/archdesc/descgrp/acqinfo/*[local-name()!="head"]')
458
- to_field 'acqinfo_ssim', extract_xpath('./acqinfo/*[local-name()!="head"]')
459
- to_field 'acqinfo_ssim', extract_xpath('./descgrp/acqinfo/*[local-name()!="head"]')
460
-
461
- to_field 'language_ssm', extract_xpath('./did/langmaterial')
462
- to_field 'containers_ssim' do |record, accumulator|
463
- record.xpath('./did/container').each do |node|
464
- accumulator << [node.attribute('type'), node.text].join(' ').strip
297
+ end.new
298
+
299
+ component_indexer = Traject::Indexer::NokogiriIndexer.new.tap do |i|
300
+ i.settings do
301
+ provide :parent, context
302
+ provide :root, context
303
+ provide :counter, counter
304
+ provide :depth, 1
305
+ provide :logger, context.settings[:logger]
306
+ provide :component_traject_config, context.settings[:component_traject_config]
465
307
  end
466
- end
467
308
 
468
- SEARCHABLE_NOTES_FIELDS.map do |selector|
469
- to_field "#{selector}_ssm", extract_xpath("./#{selector}/*[local-name()!='head']", to_text: false)
470
- to_field "#{selector}_heading_ssm", extract_xpath("./#{selector}/head")
471
- to_field "#{selector}_teim", extract_xpath("./#{selector}/*[local-name()!='head']")
472
- end
473
- DID_SEARCHABLE_NOTES_FIELDS.map do |selector|
474
- to_field "#{selector}_ssm", extract_xpath("./did/#{selector}", to_text: false)
309
+ i.load_config_file(context.settings[:component_traject_config])
475
310
  end
476
- to_field 'did_note_ssm', extract_xpath('./did/note')
477
- end
478
311
 
479
- each_record do |_record, context|
480
- context.output_hash['components'] &&= context.output_hash['components'].select { |c| c.keys.any? }
481
- end
482
-
483
- ##
484
- # Used for evaluating xpath components to find
485
- class NokogiriXpathExtensions
486
- # rubocop:disable Naming/PredicateName, Style/FormatString
487
- def is_component(node_set)
488
- node_set.find_all do |node|
489
- component_elements = (1..12).map { |i| "c#{'%02d' % i}" }
490
- component_elements.push 'c'
491
- component_elements.include? node.name
492
- end
312
+ child_components.each do |child_component|
313
+ output = component_indexer.map_record(child_component)
314
+ accumulator << output if output.keys.any?
493
315
  end
494
- # rubocop:enable Naming/PredicateName, Style/FormatString
495
316
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Arclight
4
- VERSION = '0.4.0'
4
+ VERSION = '1.6.2'
5
5
  end
@@ -18,7 +18,6 @@ module Arclight
18
18
  def initialize(dates = nil)
19
19
  @years = []
20
20
  self << parse_ranges(dates) if dates.present?
21
- self
22
21
  end
23
22
 
24
23
  # @return [String] a concise, human-readable version of the year range, including gaps
@@ -77,13 +76,14 @@ module Arclight
77
76
  # Deals with making a human-readable range for years with 1 or more gaps.
78
77
  # It involves detection of streaks between the gaps.
79
78
  # @return [String] 1999-2000, 2002 for 1999, 2000, 2002
80
- def to_s_with_gaps # rubocop: disable Metrics/AbcSize, Metrics/MethodLength
79
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
80
+ def to_s_with_gaps
81
81
  raise ArgumentError if years.blank? || years.length < 2
82
82
 
83
83
  results = []
84
84
  streak = [years[0]]
85
85
  i = streak.first
86
- years[1..-1].each do |j|
86
+ years[1..].each do |j|
87
87
  i += 1
88
88
  if i == j
89
89
  streak << j
@@ -100,6 +100,7 @@ module Arclight
100
100
  results << to_s_for_streak(streak)
101
101
  results.join(', ')
102
102
  end
103
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
103
104
 
104
105
  def to_s_for_streak(streak)
105
106
  return streak.min.to_s if streak.min == streak.max
data/lib/arclight.rb CHANGED
@@ -5,6 +5,11 @@ require 'arclight/engine'
5
5
  require 'arclight/repository'
6
6
  require 'arclight/year_range'
7
7
 
8
+ # :nodoc:
8
9
  module Arclight
9
- # Your code goes here...
10
+ autoload :Routes, 'arclight/routes'
11
+
12
+ def self.deprecation
13
+ @deprecation ||= ActiveSupport::Deprecation.new('2.0', 'Arclight')
14
+ end
10
15
  end