arclight 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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