arclight 0.2.0 → 0.3.0

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 (153) hide show
  1. checksums.yaml +4 -4
  2. data/.all-contributorsrc +450 -0
  3. data/.babelrc +3 -0
  4. data/.codeclimate.yml +5 -0
  5. data/.eslintrc +3 -0
  6. data/.rubocop.yml +19 -0
  7. data/.rubocop_todo.yml +15 -135
  8. data/.travis.yml +2 -2
  9. data/CONTRIBUTORS.md +79 -0
  10. data/README.md +21 -24
  11. data/Rakefile +0 -1
  12. data/app/assets/images/blacklight/bookmark.svg +1 -0
  13. data/app/assets/images/blacklight/collection.svg +5 -0
  14. data/app/assets/images/blacklight/compact.svg +1 -25
  15. data/app/assets/images/blacklight/container.svg +5 -0
  16. data/app/assets/images/blacklight/ead.svg +1 -0
  17. data/app/assets/images/blacklight/file.svg +5 -0
  18. data/app/assets/images/blacklight/folder.svg +1 -0
  19. data/app/assets/images/blacklight/list.svg +1 -0
  20. data/app/assets/images/blacklight/minus.svg +1 -0
  21. data/app/assets/images/blacklight/online.svg +5 -0
  22. data/app/assets/images/blacklight/pdf.svg +1 -0
  23. data/app/assets/images/blacklight/plus.svg +1 -0
  24. data/app/assets/images/blacklight/repository.svg +1 -0
  25. data/app/assets/javascripts/arclight/arclight.js +1 -3
  26. data/app/assets/javascripts/arclight/collection_navigation.js +36 -53
  27. data/app/assets/javascripts/arclight/collection_scrollspy.js +1 -1
  28. data/app/assets/javascripts/arclight/context_navigation.js +374 -0
  29. data/app/assets/javascripts/arclight/truncator.js.erb +8 -2
  30. data/app/assets/stylesheets/arclight/application.scss +3 -1
  31. data/app/assets/stylesheets/arclight/bootstrap_overrides.scss +23 -0
  32. data/app/assets/stylesheets/arclight/modules/context_navigation.scss +75 -0
  33. data/app/assets/stylesheets/arclight/modules/hierarchy_and_online_contents.scss +28 -35
  34. data/app/assets/stylesheets/arclight/modules/highlights.scss +2 -1
  35. data/app/assets/stylesheets/arclight/modules/layout.scss +128 -14
  36. data/app/assets/stylesheets/arclight/modules/mastheads.scss +27 -5
  37. data/app/assets/stylesheets/arclight/modules/repositories.scss +1 -5
  38. data/app/assets/stylesheets/arclight/modules/repository_card.scss +6 -7
  39. data/app/assets/stylesheets/arclight/modules/search_results.scss +145 -24
  40. data/app/assets/stylesheets/arclight/modules/show_collection.scss +38 -59
  41. data/app/assets/stylesheets/arclight/responsive.scss +13 -0
  42. data/app/assets/stylesheets/arclight/variables.scss +21 -1
  43. data/app/controllers/concerns/arclight/ead_format_helpers.rb +225 -0
  44. data/app/controllers/concerns/arclight/field_config_helpers.rb +23 -7
  45. data/app/factories/blacklight_field_configuration_factory.rb +1 -0
  46. data/app/helpers/arclight_helper.rb +197 -35
  47. data/app/models/arclight/document_downloads.rb +125 -0
  48. data/app/models/arclight/parent.rb +4 -2
  49. data/app/models/arclight/parents.rb +6 -4
  50. data/app/models/arclight/requests/aeon_external_request.rb +42 -0
  51. data/app/models/arclight/requests/aeon_web_ead.rb +47 -0
  52. data/app/models/arclight/requests/google_form.rb +2 -2
  53. data/app/models/concerns/arclight/catalog.rb +14 -2
  54. data/app/models/concerns/arclight/search_behavior.rb +27 -12
  55. data/app/models/concerns/arclight/solr_document.rb +29 -7
  56. data/app/views/arclight/_requests.html.erb +7 -0
  57. data/app/views/arclight/repositories/_in_person_repository.html.erb +1 -1
  58. data/app/views/arclight/repositories/_repository.html.erb +2 -2
  59. data/app/views/arclight/repositories/_repository_contact.html.erb +9 -0
  60. data/app/views/arclight/repositories/index.html.erb +3 -0
  61. data/app/views/arclight/repositories/show.html.erb +5 -4
  62. data/app/views/arclight/requests/_aeon_external_request_endpoint.html.erb +9 -0
  63. data/app/views/arclight/requests/_aeon_web_ead.html.erb +7 -0
  64. data/app/views/arclight/requests/_google_form.html.erb +2 -1
  65. data/app/views/arclight/viewers/_oembed.html.erb +2 -1
  66. data/app/views/catalog/_access_contents.html.erb +15 -0
  67. data/app/views/catalog/_arclight_abstract_or_scope.html.erb +5 -0
  68. data/app/views/catalog/_arclight_bookmark_control.html.erb +38 -0
  69. data/app/views/catalog/_arclight_document_header_icon.html.erb +1 -0
  70. data/app/views/catalog/_arclight_index_compact_default.html.erb +18 -11
  71. data/app/views/catalog/_arclight_index_default.html.erb +45 -0
  72. data/app/views/catalog/_arclight_index_group_document_compact_default.html.erb +19 -0
  73. data/app/views/catalog/_arclight_index_group_document_default.html.erb +18 -0
  74. data/app/views/catalog/_arclight_online_content_indicator.html.erb +1 -3
  75. data/app/views/catalog/_collection_contents.html.erb +2 -10
  76. data/app/views/catalog/_collection_context.html.erb +15 -0
  77. data/app/views/catalog/_collection_context_nav.html.erb +12 -0
  78. data/app/views/catalog/_collection_online_contents.html.erb +3 -3
  79. data/app/views/catalog/_component_context.html.erb +5 -0
  80. data/app/views/catalog/_containers.html.erb +3 -0
  81. data/app/views/catalog/_context_sidebar.html.erb +2 -2
  82. data/app/views/catalog/_document_downloads.html.erb +14 -0
  83. data/app/views/catalog/_group.html.erb +21 -0
  84. data/app/views/catalog/_group_header_compact_default.html.erb +15 -0
  85. data/app/views/catalog/_group_header_default.html.erb +20 -0
  86. data/app/views/catalog/_group_toggle.html.erb +10 -0
  87. data/app/views/catalog/_home.html.erb +1 -1
  88. data/app/views/catalog/_index_breadcrumb_default.html.erb +5 -2
  89. data/app/views/catalog/_index_collection_context_default.html.erb +53 -0
  90. data/app/views/catalog/_index_header.html.erb +3 -3
  91. data/app/views/catalog/_index_online_contents_default.html.erb +1 -1
  92. data/app/views/catalog/_online_content_label.html.erb +5 -0
  93. data/app/views/catalog/_search_form.html.erb +34 -0
  94. data/app/views/catalog/_search_results.html.erb +1 -4
  95. data/app/views/catalog/_show_actions_box_default.html.erb +27 -0
  96. data/app/views/catalog/_show_breadcrumbs_default.html.erb +5 -20
  97. data/app/views/catalog/_show_collection.html.erb +42 -24
  98. data/app/views/catalog/_show_default.html.erb +63 -35
  99. data/app/views/catalog/_show_upper_metadata_default.html.erb +1 -1
  100. data/app/views/catalog/_sort_and_per_page.html.erb +8 -0
  101. data/app/views/catalog/_within_collection_dropdown.html.erb +26 -0
  102. data/app/views/shared/_breadcrumbs.html.erb +4 -4
  103. data/app/views/shared/_context_sidebar.html.erb +2 -2
  104. data/app/views/shared/_header_navbar.html.erb +13 -17
  105. data/app/views/shared/_show_breadcrumbs.html.erb +27 -0
  106. data/arclight.gemspec +5 -6
  107. data/config/i18n-tasks.yml +2 -1
  108. data/config/locales/arclight.en.yml +54 -21
  109. data/config/repositories.yml +0 -0
  110. data/lib/arclight/engine.rb +22 -12
  111. data/lib/arclight/hash_absolute_xpath.rb +11 -7
  112. data/lib/arclight/level_label.rb +46 -0
  113. data/lib/arclight/normalized_date.rb +2 -2
  114. data/lib/arclight/normalized_id.rb +1 -0
  115. data/lib/arclight/normalized_title.rb +1 -0
  116. data/lib/arclight/repository.rb +58 -5
  117. data/lib/arclight/traject/ead2_config.rb +178 -159
  118. data/lib/arclight/traject/nokogiri_namespaceless_reader.rb +22 -0
  119. data/lib/arclight/version.rb +1 -1
  120. data/lib/arclight/viewers/oembed.rb +1 -0
  121. data/lib/arclight/year_range.rb +9 -1
  122. data/lib/generators/arclight/install_generator.rb +5 -1
  123. data/lib/generators/arclight/templates/catalog_controller.rb +128 -100
  124. data/lib/generators/arclight/templates/config/downloads.yml +12 -0
  125. data/lib/generators/arclight/templates/config/repositories.yml +20 -2
  126. data/lib/generators/arclight/update_generator.rb +1 -1
  127. data/lib/tasks/index.rake +18 -20
  128. data/package.json +8 -1
  129. data/solr/conf/schema.xml +51 -292
  130. data/solr/conf/solrconfig.xml +40 -125
  131. data/tasks/arclight.rake +1 -0
  132. data/vendor/assets/javascripts/responsiveTruncator.js +2 -2
  133. metadata +71 -44
  134. data/app/assets/javascripts/arclight/collection_context.js +0 -18
  135. data/app/assets/javascripts/arclight/component_ancestors.js +0 -56
  136. data/app/assets/javascripts/arclight/search_results.js +0 -15
  137. data/app/assets/stylesheets/arclight/modules/sidebar.scss +0 -21
  138. data/app/views/catalog/_collection_count.html.erb +0 -7
  139. data/app/views/catalog/_collection_downloads.html.erb +0 -15
  140. data/app/views/catalog/_collection_overview.html.erb +0 -7
  141. data/app/views/catalog/_component_contents.html.erb +0 -16
  142. data/app/views/catalog/_component_overview.html.erb +0 -40
  143. data/app/views/catalog/_index_header_hierarchy_default.html.erb +0 -42
  144. data/app/views/catalog/_index_hierarchy_default.html.erb +0 -28
  145. data/app/views/catalog/_results_histogram.html.erb +0 -15
  146. data/app/views/catalog/_show_component_sidebar.html.erb +0 -12
  147. data/app/views/catalog/_show_sidebar.html.erb +0 -22
  148. data/lib/arclight/custom_component.rb +0 -99
  149. data/lib/arclight/custom_document.rb +0 -93
  150. data/lib/arclight/indexer.rb +0 -9
  151. data/lib/arclight/shared_indexing_behavior.rb +0 -97
  152. data/lib/arclight/shared_terminology_behavior.rb +0 -65
  153. data/lib/arclight/solr_ead_indexer_ext.rb +0 -155
@@ -1,9 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Arclight
4
- ##
5
- # A simple wrapper class around the SolrEad::Indexer so we can add our own behavior
6
- class Indexer < SolrEad::Indexer
7
- include Arclight::SolrEadIndexerExt
8
- end
9
- end
@@ -1,97 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Arclight
4
- ##
5
- # A mixin intended to share indexing behavior between
6
- # the CustomDocument and CustomComponent classes
7
- module SharedIndexingBehavior
8
- # @see http://eadiva.com/2/unitdate/
9
- # @return [YearRange] all of the years between the given years
10
- def unitdate_for_range
11
- range = YearRange.new
12
- return range if normal_unit_dates.blank?
13
- range << range.parse_ranges(normal_unit_dates)
14
- range
15
- end
16
-
17
- def subjects_array(elements, parent:)
18
- xpath_elements = elements.map { |el| "local-name()='#{el}'" }.join(' or ')
19
- subjects = search("//#{parent}/controlaccess/*[#{xpath_elements}]").to_a
20
- clean_facets_array(subjects.flatten.map(&:text))
21
- end
22
-
23
- def names_array(elements, parent:)
24
- xpath_elements = elements.map { |el| "local-name()='#{el}'" }.join(' or ')
25
- names = search("//#{parent}/controlaccess/*[#{xpath_elements}]").to_a
26
- clean_facets_array(names.flatten.map(&:text))
27
- end
28
-
29
- # Return a cleaned array of facets without marc subfields
30
- #
31
- # E.g. clean_facets_array(
32
- # ['FacetValue1 |z FacetValue2','FacetValue3']
33
- # ) => ['FacetValue1 -- FacetValue2', 'FacetValue3']
34
- def clean_facets_array(facets_array)
35
- Array(facets_array).map { |text| fix_subfield_demarcators(text) }.compact.uniq
36
- end
37
-
38
- # Replace MARC style subfield demarcators
39
- #
40
- # Usage: fix_subfield_demarcators("Subject 1 |z Sub-Subject 2") => "Subject 1 -- Sub-Subject 2"
41
- def fix_subfield_demarcators(value)
42
- value.gsub(/\|\w{1}/, '--')
43
- end
44
-
45
- # Wrap OM's find_by_xpath for convenience
46
- def search(path)
47
- find_by_xpath(path) # rubocop:disable DynamicFindBy
48
- end
49
-
50
- # If a repository slug is provided via an environment variable `REPOSITORY_ID`,
51
- # then use that to lookup the name rather than the parsed out name from the EAD
52
- # @param [String] `repository` the default repository name
53
- def repository_as_configured(repository)
54
- slug = ENV['REPOSITORY_ID']
55
- if slug.present?
56
- begin
57
- Arclight::Repository.find_by(slug: slug).name
58
- rescue => e
59
- raise "The repository slug '#{slug}' was given but it is not found in the Repository configuration data: #{e}"
60
- end
61
- else
62
- repository
63
- end
64
- end
65
-
66
- def add_digital_content(prefix:, solr_doc:)
67
- dao = ng_xml.xpath("#{prefix}/dao").to_a
68
- return if dao.blank?
69
- field_name = Solrizer.solr_name('digital_objects', :displayable)
70
- solr_doc[field_name] = digital_objects(dao)
71
- end
72
-
73
- def digital_objects(objects)
74
- objects.map do |dao|
75
- label = dao.attributes['title'].try(:value) || dao.xpath('daodesc/p').try(:text)
76
- href = (dao.attributes['href'] || dao.attributes['xlink:href']).try(:value)
77
- Arclight::DigitalObject.new(label: label, href: href).to_json
78
- end
79
- end
80
-
81
- def add_date_ranges(solr_doc)
82
- Solrizer.insert_field(solr_doc, 'date_range', unitdate_for_range.years, :facetable)
83
- end
84
-
85
- def add_normalized_title(solr_doc)
86
- dates = Arclight::NormalizedDate.new(unitdate_inclusive, unitdate_bulk, unitdate_other).to_s
87
- title = Arclight::NormalizedTitle.new(solr_doc['title_ssm'].try(:first), dates).to_s
88
- solr_doc['normalized_title_ssm'] = [title]
89
- solr_doc['normalized_date_ssm'] = [dates]
90
- title
91
- end
92
-
93
- def online_content?
94
- search('//dao[@href]').present?
95
- end
96
- end
97
- end
@@ -1,65 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Arclight
4
- ##
5
- # An extendable mixin intended to share terminology behavior between
6
- # the CustomDocument and CustomComponent classes
7
- module SharedTerminologyBehavior
8
- def add_unitid(t, prefix)
9
- t.unitid(path: prefix + 'did/unitid', index_as: %i[displayable searchable])
10
- end
11
-
12
- def add_extent(t, prefix)
13
- t.extent(path: prefix + 'did/physdesc/extent', index_as: %i[displayable searchable])
14
- end
15
-
16
- # date indexing
17
- def add_dates(t, prefix)
18
- t.normal_unit_dates(path: prefix + 'did/unitdate/@normal')
19
- t.unitdate_bulk(path: prefix + 'did/unitdate[@type=\'bulk\']', index_as: %i[displayable])
20
- t.unitdate_inclusive(path: prefix + 'did/unitdate[@type=\'inclusive\']', index_as: %i[displayable])
21
- t.unitdate_other(path: prefix + 'did/unitdate[not(@type)]', index_as: %i[displayable])
22
- t.unitdate(path: prefix + 'did/unitdate', index_as: %i[displayable])
23
- end
24
-
25
- def add_searchable_notes(t, prefix) # rubocop: disable Metrics/MethodLength
26
- # various searchable notes
27
- %i[
28
- accessrestrict
29
- accruals
30
- acqinfo
31
- altformavail
32
- appraisal
33
- arrangement
34
- bibliography
35
- bioghist
36
- custodhist
37
- fileplan
38
- note
39
- odd
40
- originalsloc
41
- otherfindaid
42
- phystech
43
- prefercite
44
- processinfo
45
- relatedmaterial
46
- scopecontent
47
- separatedmaterial
48
- userestrict
49
- ].each do |k|
50
- # many of the notes support various markup so we want everything but the heading
51
- t.send(k, path: "#{prefix}#{k}/*[local-name()!=\"head\"]", index_as: %i[displayable searchable])
52
- end
53
-
54
- # various searchable notes in the did
55
- %i[
56
- abstract
57
- materialspec
58
- physloc
59
- ].each do |k|
60
- t.send(k, path: "#{prefix}did/#{k}", index_as: %i[displayable searchable])
61
- end
62
- t.did_note(path: "#{prefix}did/note", index_as: %i[displayable searchable]) # conflicts with top-level note
63
- end
64
- end
65
- end
@@ -1,155 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Arclight
4
- ##
5
- # An module to extend SolrEad::Indexer behaviors to allow us to add
6
- # or override behaviors that require knowledge of the entire XML document.
7
- module SolrEadIndexerExt
8
- def additional_component_fields(node, addl_fields = {})
9
- solr_doc = super
10
-
11
- add_count_of_child_compontents(node, solr_doc)
12
- add_ancestral_titles(node, solr_doc)
13
- add_ancestral_ids(node, solr_doc)
14
-
15
- add_collection_creator_to_component(node, solr_doc)
16
-
17
- add_self_or_parents_restrictions(node, solr_doc)
18
-
19
- add_self_or_parents_terms(node, solr_doc)
20
-
21
- solr_doc
22
- end
23
-
24
- def delete_all
25
- solr.delete_by_query('*:*')
26
- solr.commit
27
- end
28
-
29
- private
30
-
31
- # Note that we need to redo what solr_ead does for ids due to our normalization process
32
- def add_ancestral_ids(node, solr_doc)
33
- @parent_id_name ||= Solrizer.solr_name('parent', :stored_sortable)
34
- @parent_ids_field_name ||= Solrizer.solr_name('parent', :displayable)
35
- @parent_ids_search_field_name ||= Solrizer.solr_name('parent', :searchable)
36
-
37
- ids = ancestral_ids(node)
38
- solr_doc[@parent_ids_field_name] = ids
39
- solr_doc[@parent_ids_search_field_name] = ids
40
- solr_doc[@parent_id_name] = ids.last
41
- end
42
-
43
- # Note that we need to redo what solr_ead does for titles due to our normalization process
44
- def add_ancestral_titles(node, solr_doc)
45
- @parent_titles_field_name ||= Solrizer.solr_name('parent_unittitles', :displayable)
46
- @parent_titles_search_field_name ||= Solrizer.solr_name('parent_unittitles', :searchable)
47
- @collection_facet_name ||= Solrizer.solr_name('collection', :facetable)
48
- @collection_name ||= Solrizer.solr_name('collection', :displayable)
49
-
50
- titles = ancestral_titles(node)
51
- solr_doc[@parent_titles_field_name] = titles
52
- solr_doc[@parent_titles_search_field_name] = titles
53
- solr_doc[@collection_name] = [titles.first] # collection is always on top
54
- solr_doc[@collection_facet_name] = [titles.first]
55
- end
56
-
57
- def add_count_of_child_compontents(node, solr_doc)
58
- @child_component_count_name ||= Solrizer.solr_name('child_component_count', type: :integer)
59
-
60
- solr_doc[@child_component_count_name] = node.xpath('count(c)').to_i
61
- end
62
-
63
- def ancestral_ids(node)
64
- ancestral_visit(node, :normalized_component_id, :normalized_collection_id)
65
- end
66
-
67
- def ancestral_titles(node)
68
- ancestral_visit(node, :normalized_component_title, :normalized_collection_title)
69
- end
70
-
71
- # visit each component's parent and finish with a visit on the collection
72
- def ancestral_visit(node, component_fn, collection_fn, results = [])
73
- while node.parent && node.parent.name == 'c'
74
- parent = node.parent
75
- results << send(component_fn, parent)
76
- node = parent
77
- end
78
- results << send(collection_fn, node)
79
- results.reverse
80
- end
81
-
82
- def normalized_component_title(node)
83
- data = extract_title_and_dates(node)
84
- normalize_title(data)
85
- end
86
-
87
- def normalized_collection_title(node)
88
- data = extract_title_and_dates(node, '//archdesc/')
89
- normalize_title(data)
90
- end
91
-
92
- def normalize_title(data)
93
- Arclight::NormalizedTitle.new(
94
- data[:title],
95
- Arclight::NormalizedDate.new(
96
- data[:unitdate_inclusive],
97
- data[:unitdate_bulk],
98
- data[:unitdate_other]
99
- ).to_s
100
- ).to_s
101
- end
102
-
103
- # TODO: these xpaths should be DRY'd up -- they're in both terminologies
104
- def extract_title_and_dates(node, prefix = nil)
105
- {
106
- title: node.at_xpath("#{prefix}did/unittitle").try(:text),
107
- unitdate_inclusive: node.xpath("#{prefix}did/unitdate[@type=\"inclusive\"]").map(&:text),
108
- unitdate_bulk: node.xpath("#{prefix}did/unitdate[@type=\"bulk\"]").map(&:text),
109
- unitdate_other: node.xpath("#{prefix}did/unitdate[not(@type)]").map(&:text)
110
- }
111
- end
112
-
113
- def normalized_component_id(node)
114
- Arclight::NormalizedId.new(node['id'].to_s).to_s
115
- end
116
-
117
- def normalized_collection_id(node)
118
- Arclight::NormalizedId.new(node.document.at_xpath('//eadid').text).to_s
119
- end
120
-
121
- # This mimics similar behavior in Arclight::CustomDocument
122
- def add_collection_creator_to_component(node, solr_doc)
123
- field_name = Solrizer.solr_name('collection_creator', :displayable)
124
- repository = solr_doc[Solrizer.solr_name('repository', :displayable)]
125
- creators = node.xpath('//archdesc/did/origination[@label="creator"]/*/text()').map(&:text)
126
- solr_doc[field_name] = creators - [repository]
127
- end
128
-
129
- def parent_check_list(node, root_path, element_path, results = [])
130
- orginal_node = node
131
- results = node.xpath("#{root_path}/#{element_path}").map(&:text)
132
- # if current restriction return, else go up to parent and check
133
- while node.parent.name == 'c' && results.blank?
134
- parent = node.parent
135
- results = parent.xpath("#{root_path}/#{element_path}").map(&:text)
136
- node = parent
137
- end
138
- # If no parental results, check the collection
139
- results = orginal_node.xpath("//archdesc/#{element_path}").map(&:text) if results.blank?
140
- results.flatten # can't use with flatten! because that returns nil
141
- end
142
-
143
- def add_self_or_parents_restrictions(node, solr_doc)
144
- field_name = Solrizer.solr_name('parent_access_restrict', :displayable)
145
- solr_doc[field_name] = parent_check_list(node, './', 'accessrestrict/p/text()')
146
- solr_doc[field_name]
147
- end
148
-
149
- def add_self_or_parents_terms(node, solr_doc)
150
- field_name = Solrizer.solr_name('parent_access_terms', :displayable)
151
- solr_doc[field_name] = parent_check_list(node, './', 'userestrict/p/text()')
152
- solr_doc[field_name]
153
- end
154
- end
155
- end