arclight 0.0.1 → 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.
- checksums.yaml +5 -5
- data/.all-contributorsrc +450 -0
- data/.codeclimate.yml +5 -0
- data/.eslintrc +22 -0
- data/.github/workflows/ruby.yml +51 -0
- data/.gitignore +7 -0
- data/.rspec +0 -1
- data/.rubocop.yml +521 -0
- data/.rubocop_todo.yml +122 -0
- data/.solr_wrapper +6 -0
- data/CONTRIBUTING.md +43 -0
- data/CONTRIBUTORS.md +79 -0
- data/Gemfile +41 -0
- data/LICENSE.txt +1 -0
- data/README.md +100 -12
- data/Rakefile +13 -3
- data/app/assets/images/arclight/logo.png +0 -0
- data/app/assets/images/blacklight/bookmark.svg +1 -0
- data/app/assets/images/blacklight/collection.svg +5 -0
- data/app/assets/images/blacklight/compact.svg +1 -0
- data/app/assets/images/blacklight/container.svg +5 -0
- data/app/assets/images/blacklight/ead.svg +1 -0
- data/app/assets/images/blacklight/file.svg +5 -0
- data/app/assets/images/blacklight/folder.svg +1 -0
- data/app/assets/images/blacklight/list.svg +1 -0
- data/app/assets/images/blacklight/minus.svg +1 -0
- data/app/assets/images/blacklight/online.svg +5 -0
- data/app/assets/images/blacklight/pdf.svg +1 -0
- data/app/assets/images/blacklight/plus.svg +1 -0
- data/app/assets/images/blacklight/repository.svg +1 -0
- data/app/assets/javascripts/arclight/arclight.js +4 -0
- data/app/assets/javascripts/arclight/oembed_controller.js +58 -0
- data/app/assets/javascripts/arclight/truncate_controller.js +27 -0
- data/app/assets/stylesheets/arclight/application.scss +14 -0
- data/app/assets/stylesheets/arclight/build.scss +4 -0
- data/app/assets/stylesheets/arclight/modules/collection_search.scss +3 -0
- data/app/assets/stylesheets/arclight/modules/hierarchy_and_online_contents.scss +155 -0
- data/app/assets/stylesheets/arclight/modules/highlights.scss +11 -0
- data/app/assets/stylesheets/arclight/modules/icons.scss +20 -0
- data/app/assets/stylesheets/arclight/modules/layout.scss +220 -0
- data/app/assets/stylesheets/arclight/modules/mastheads.scss +42 -0
- data/app/assets/stylesheets/arclight/modules/repositories.scss +25 -0
- data/app/assets/stylesheets/arclight/modules/repository_card.scss +9 -0
- data/app/assets/stylesheets/arclight/modules/search_form.scss +9 -0
- data/app/assets/stylesheets/arclight/modules/search_results.scss +250 -0
- data/app/assets/stylesheets/arclight/modules/show_collection.scss +38 -0
- data/app/assets/stylesheets/arclight/modules/truncator.scss +58 -0
- data/app/assets/stylesheets/arclight/responsive.scss +13 -0
- data/app/assets/stylesheets/arclight/variables.scss +25 -0
- data/app/components/arclight/access_component.html.erb +14 -0
- data/app/components/arclight/access_component.rb +25 -0
- data/app/components/arclight/bookmark_component.html.erb +25 -0
- data/app/components/arclight/bookmark_component.rb +9 -0
- data/app/components/arclight/breadcrumb_component.rb +50 -0
- data/app/components/arclight/breadcrumbs_hierarchy_component.html.erb +34 -0
- data/app/components/arclight/breadcrumbs_hierarchy_component.rb +25 -0
- data/app/components/arclight/collection_context_component.html.erb +12 -0
- data/app/components/arclight/collection_context_component.rb +27 -0
- data/app/components/arclight/collection_info_component.html.erb +28 -0
- data/app/components/arclight/collection_info_component.rb +26 -0
- data/app/components/arclight/collection_sidebar_component.html.erb +15 -0
- data/app/components/arclight/collection_sidebar_component.rb +39 -0
- data/app/components/arclight/constraints_component.html.erb +7 -0
- data/app/components/arclight/constraints_component.rb +17 -0
- data/app/components/arclight/document_collection_context_component.html.erb +29 -0
- data/app/components/arclight/document_collection_context_component.rb +28 -0
- data/app/components/arclight/document_collection_hierarchy_component.html.erb +50 -0
- data/app/components/arclight/document_collection_hierarchy_component.rb +62 -0
- data/app/components/arclight/document_component.html.erb +39 -0
- data/app/components/arclight/document_component.rb +49 -0
- data/app/components/arclight/document_components_hierarchy_component.html.erb +20 -0
- data/app/components/arclight/document_components_hierarchy_component.rb +34 -0
- data/app/components/arclight/document_download_component.html.erb +24 -0
- data/app/components/arclight/document_download_component.rb +71 -0
- data/app/components/arclight/embed_component.html.erb +10 -0
- data/app/components/arclight/embed_component.rb +43 -0
- data/app/components/arclight/expand_hierarchy_button_component.html.erb +5 -0
- data/app/components/arclight/expand_hierarchy_button_component.rb +16 -0
- data/app/components/arclight/group_component.html.erb +34 -0
- data/app/components/arclight/group_component.rb +23 -0
- data/app/components/arclight/header_component.html.erb +5 -0
- data/app/components/arclight/header_component.rb +10 -0
- data/app/components/arclight/index_metadata_field_component.html.erb +16 -0
- data/app/components/arclight/index_metadata_field_component.rb +20 -0
- data/app/components/arclight/masthead_component.html.erb +17 -0
- data/app/components/arclight/masthead_component.rb +10 -0
- data/app/components/arclight/metadata_section_component.html.erb +13 -0
- data/app/components/arclight/metadata_section_component.rb +22 -0
- data/app/components/arclight/oembed_viewer_component.html.erb +5 -0
- data/app/components/arclight/oembed_viewer_component.rb +16 -0
- data/app/components/arclight/online_content_filter_component.html.erb +15 -0
- data/app/components/arclight/online_content_filter_component.rb +17 -0
- data/app/components/arclight/online_status_indicator_component.rb +19 -0
- data/app/components/arclight/repository_breadcrumb_component.html.erb +10 -0
- data/app/components/arclight/repository_breadcrumb_component.rb +17 -0
- data/app/components/arclight/repository_location_component.html.erb +20 -0
- data/app/components/arclight/repository_location_component.rb +10 -0
- data/app/components/arclight/search_bar_component.html.erb +27 -0
- data/app/components/arclight/search_bar_component.rb +32 -0
- data/app/components/arclight/search_result_breadcrumbs_component.html.erb +6 -0
- data/app/components/arclight/search_result_breadcrumbs_component.rb +37 -0
- data/app/components/arclight/search_result_component.html.erb +20 -0
- data/app/components/arclight/search_result_component.rb +18 -0
- data/app/components/arclight/search_result_title_component.html.erb +15 -0
- data/app/components/arclight/search_result_title_component.rb +15 -0
- data/app/components/arclight/sidebar_component.html.erb +9 -0
- data/app/components/arclight/sidebar_component.rb +19 -0
- data/app/components/arclight/upper_metadata_layout_component.rb +10 -0
- data/app/components/blacklight/icons/bookmark_component.rb +12 -0
- data/app/components/blacklight/icons/collection_component.rb +14 -0
- data/app/components/blacklight/icons/compact_component.rb +12 -0
- data/app/components/blacklight/icons/container_component.rb +14 -0
- data/app/components/blacklight/icons/ead_component.rb +12 -0
- data/app/components/blacklight/icons/file_component.rb +14 -0
- data/app/components/blacklight/icons/folder_component.rb +12 -0
- data/app/components/blacklight/icons/online_component.rb +15 -0
- data/app/components/blacklight/icons/pdf_component.rb +12 -0
- data/app/components/blacklight/icons/repository_component.rb +12 -0
- data/app/controllers/arclight/repositories_controller.rb +40 -0
- data/app/helpers/arclight/ead_format_helpers.rb +309 -0
- data/app/helpers/arclight/field_config_helpers.rb +26 -0
- data/app/helpers/arclight_helper.rb +108 -0
- data/app/models/arclight/document_downloads.rb +122 -0
- data/app/models/arclight/parent.rb +24 -0
- data/app/models/arclight/parents.rb +39 -0
- data/app/models/arclight/requests/aeon_external_request.rb +42 -0
- data/app/models/arclight/requests/aeon_web_ead.rb +52 -0
- data/app/models/arclight/requests/google_form.rb +49 -0
- data/app/models/concerns/arclight/catalog.rb +44 -0
- data/app/models/concerns/arclight/search_behavior.rb +47 -0
- data/app/models/concerns/arclight/solr_document.rb +160 -0
- data/app/presenters/arclight/index_presenter.rb +10 -0
- data/app/presenters/arclight/show_presenter.rb +54 -0
- data/app/views/arclight/.keep +0 -0
- data/app/views/arclight/_requests.html.erb +7 -0
- data/app/views/arclight/repositories/_repository.html.erb +43 -0
- data/app/views/arclight/repositories/index.html.erb +9 -0
- data/app/views/arclight/repositories/show.html.erb +37 -0
- data/app/views/arclight/requests/_aeon_external_request_endpoint.html.erb +8 -0
- data/app/views/arclight/requests/_aeon_web_ead.html.erb +6 -0
- data/app/views/arclight/requests/_google_form.html.erb +10 -0
- data/app/views/catalog/_document_list.html.erb +8 -0
- data/app/views/catalog/_group.html.erb +4 -0
- data/app/views/catalog/_group_toggle.html.erb +10 -0
- data/app/views/catalog/_search_results_header.html.erb +3 -0
- data/app/views/catalog/hierarchy.html.erb +19 -0
- data/app/views/catalog/index.html.erb +17 -0
- data/app/views/shared/_breadcrumbs.html.erb +3 -0
- data/app/views/shared/_main_menu_links.html.erb +6 -0
- data/arclight.gemspec +29 -11
- data/bin/rails +13 -0
- data/config/breadcrumbs.rb +24 -0
- data/config/i18n-tasks.yml +134 -0
- data/config/importmap.rb +3 -0
- data/config/locales/arclight.en.yml +100 -0
- data/config/repositories.yml +0 -0
- data/config/routes.rb +6 -0
- data/docker-compose.yml +16 -0
- data/lib/arclight/digital_object.rb +27 -0
- data/lib/arclight/engine.rb +47 -0
- data/lib/arclight/exceptions.rb +19 -0
- data/lib/arclight/hash_absolute_xpath.rb +62 -0
- data/lib/arclight/level_label.rb +46 -0
- data/lib/arclight/missing_id_strategy.rb +21 -0
- data/lib/arclight/normalized_date.rb +49 -0
- data/lib/arclight/normalized_id.rb +30 -0
- data/lib/arclight/normalized_title.rb +33 -0
- data/lib/arclight/repository.rb +116 -0
- data/lib/arclight/routes/hierarchy.rb +19 -0
- data/lib/arclight/routes.rb +8 -0
- data/lib/arclight/traject/ead2_component_config.rb +335 -0
- data/lib/arclight/traject/ead2_config.rb +316 -0
- data/lib/arclight/traject/nokogiri_namespaceless_reader.rb +22 -0
- data/lib/arclight/version.rb +3 -1
- data/lib/arclight/year_range.rb +111 -0
- data/lib/arclight.rb +11 -1
- data/lib/generators/arclight/install_generator.rb +163 -0
- data/lib/generators/arclight/templates/arclight.scss +6 -0
- data/lib/generators/arclight/templates/catalog_controller.rb +423 -0
- data/lib/generators/arclight/templates/config/downloads.yml +25 -0
- data/lib/generators/arclight/templates/config/locales/arclight.en.yml +61 -0
- data/lib/generators/arclight/templates/config/repositories.yml +53 -0
- data/lib/generators/arclight/update_generator.rb +22 -0
- data/lib/tasks/index.rake +84 -0
- data/package.json +30 -0
- data/solr/conf/_rest_managed.json +3 -0
- data/solr/conf/admin-extra.html +31 -0
- data/solr/conf/elevate.xml +36 -0
- data/solr/conf/mapping-ISOLatin1Accent.txt +246 -0
- data/solr/conf/protwords.txt +21 -0
- data/solr/conf/schema.xml +400 -0
- data/solr/conf/solrconfig.xml +328 -0
- data/solr/conf/spellings.txt +2 -0
- data/solr/conf/stopwords.txt +58 -0
- data/solr/conf/stopwords_en.txt +58 -0
- data/solr/conf/synonyms.txt +31 -0
- data/solr/conf/xslt/example.xsl +132 -0
- data/solr/conf/xslt/example_atom.xsl +67 -0
- data/solr/conf/xslt/example_rss.xsl +66 -0
- data/solr/conf/xslt/luke.xsl +337 -0
- data/tasks/arclight.rake +79 -0
- data/template.rb +10 -0
- metadata +440 -20
- data/.travis.yml +0 -5
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Arclight
|
|
4
|
+
##
|
|
5
|
+
# A module to add EAD to HTML transformation rules for Arclight
|
|
6
|
+
module EadFormatHelpers # rubocop:disable Metrics/ModuleLength
|
|
7
|
+
extend ActiveSupport::Concern
|
|
8
|
+
|
|
9
|
+
def render_html_tags(args)
|
|
10
|
+
values = Array(args[:value])
|
|
11
|
+
values.map! do |value|
|
|
12
|
+
transform_ead_to_html(value)
|
|
13
|
+
end
|
|
14
|
+
values.map! { |value| wrap_in_paragraph(value) } if values.count > 1
|
|
15
|
+
safe_join(values.map(&:html_safe))
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def transform_ead_to_html(value)
|
|
21
|
+
Loofah.xml_fragment(condense_whitespace(value))
|
|
22
|
+
.scrub!(ead_to_html_scrubber)
|
|
23
|
+
.scrub!(:strip).to_html
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# rubocop:disable Metrics/AbcSize
|
|
27
|
+
def ead_to_html_scrubber
|
|
28
|
+
Loofah::Scrubber.new do |node|
|
|
29
|
+
format_render_attributes(node) if node.attr('render').present?
|
|
30
|
+
convert_to_span(node) if CONVERT_TO_SPAN_TAGS.include? node.name
|
|
31
|
+
convert_to_br(node) if CONVERT_TO_BR_TAG.include? node.name
|
|
32
|
+
format_links(node) if %w[extptr extref extrefloc ptr ref].include? node.name
|
|
33
|
+
format_lists(node) if %w[list chronlist].include? node.name
|
|
34
|
+
format_indexes(node) if node.name == 'index'
|
|
35
|
+
format_tables(node) if node.name == 'table'
|
|
36
|
+
node
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
# rubocop:enable Metrics/AbcSize
|
|
40
|
+
|
|
41
|
+
# Tags that should be converted to <span> tags because of formatting conflicts between XML and HTML
|
|
42
|
+
CONVERT_TO_SPAN_TAGS = ['title'].freeze
|
|
43
|
+
|
|
44
|
+
# Tags that should be converted to HTML <br/> tags
|
|
45
|
+
CONVERT_TO_BR_TAG = ['lb'].freeze
|
|
46
|
+
|
|
47
|
+
def convert_to_span(node)
|
|
48
|
+
node.name = 'span'
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def convert_to_br(node)
|
|
52
|
+
node.name = 'br'
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def condense_whitespace(str)
|
|
56
|
+
str.squish.strip.gsub(/>[\n\s]+</, '><')
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def wrap_in_paragraph(value)
|
|
60
|
+
if value.start_with?('<')
|
|
61
|
+
value
|
|
62
|
+
else
|
|
63
|
+
content_tag(:p, value)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def format_render_attributes(node) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity
|
|
68
|
+
case node.attr('render')
|
|
69
|
+
when 'altrender'
|
|
70
|
+
node.name = 'span'
|
|
71
|
+
node['class'] = node['altrender']
|
|
72
|
+
when 'bold'
|
|
73
|
+
node.name = 'strong'
|
|
74
|
+
when 'bolddoublequote'
|
|
75
|
+
node.name = 'strong'
|
|
76
|
+
node.prepend_child '"'
|
|
77
|
+
node.add_child '"'
|
|
78
|
+
when 'bolditalic'
|
|
79
|
+
node.name = 'strong'
|
|
80
|
+
node.wrap('<em/>')
|
|
81
|
+
when 'boldsinglequote'
|
|
82
|
+
node.name = 'strong'
|
|
83
|
+
node.prepend_child '\''
|
|
84
|
+
node.add_child '\''
|
|
85
|
+
when 'boldsmcaps'
|
|
86
|
+
node.name = 'strong'
|
|
87
|
+
node.wrap('<small/>')
|
|
88
|
+
node['class'] = 'text-uppercase'
|
|
89
|
+
when 'boldunderline'
|
|
90
|
+
node.name = 'strong'
|
|
91
|
+
node['class'] = 'text-underline'
|
|
92
|
+
when 'doublequote'
|
|
93
|
+
node.name = 'span'
|
|
94
|
+
node.prepend_child '"'
|
|
95
|
+
node.add_child '"'
|
|
96
|
+
when 'italic', 'nonproport'
|
|
97
|
+
node.name = 'em'
|
|
98
|
+
when 'singlequote'
|
|
99
|
+
node.name = 'span'
|
|
100
|
+
node.prepend_child '\''
|
|
101
|
+
node.add_child '\''
|
|
102
|
+
when 'smcaps'
|
|
103
|
+
node.name = 'small'
|
|
104
|
+
node['class'] = 'text-uppercase'
|
|
105
|
+
when 'sub'
|
|
106
|
+
node.name = 'sub'
|
|
107
|
+
when 'super'
|
|
108
|
+
node.name = 'sup'
|
|
109
|
+
when 'underline'
|
|
110
|
+
node.name = 'span'
|
|
111
|
+
node['class'] = 'text-underline'
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def format_links(node)
|
|
116
|
+
node.remove_attribute('target')
|
|
117
|
+
node.remove_attribute('type')
|
|
118
|
+
if %w[extptr extref extrefloc].include? node.name
|
|
119
|
+
node['target'] = '_blank'
|
|
120
|
+
node['class'] = 'external-link'
|
|
121
|
+
end
|
|
122
|
+
node.content = node['title'] if (%w[extptr ptr].include? node.name) && node['title'].present?
|
|
123
|
+
node.name = 'a' if node['href'].present?
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def format_lists(node)
|
|
127
|
+
format_simple_lists(node) if node.name == 'list' && node['type'] != 'deflist'
|
|
128
|
+
format_deflists(node) if node.name == 'list' && node['type'] == 'deflist'
|
|
129
|
+
format_chronlists(node) if node.name == 'chronlist'
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def format_simple_lists(node)
|
|
133
|
+
node.name = 'ul' if (%w[simple marked].include? node['type']) || node['type'].blank?
|
|
134
|
+
node.name = 'ol' if node['type'] == 'ordered'
|
|
135
|
+
node.remove_attribute('type')
|
|
136
|
+
head_node = node.at_css('head')
|
|
137
|
+
format_list_head(head_node) if head_node.present?
|
|
138
|
+
items = node.css('item')
|
|
139
|
+
items.each { |item_node| item_node.name = 'li' }
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def format_list_head(node)
|
|
143
|
+
node['class'] = 'list-head'
|
|
144
|
+
node.name = 'div'
|
|
145
|
+
node.parent.previous = node # move it from within the list to above it
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def format_deflists(node)
|
|
149
|
+
listhead_node = node.at_css('listhead')
|
|
150
|
+
labels = node.css('label')
|
|
151
|
+
items = node.css('item')
|
|
152
|
+
defitems = node.css('defitem')
|
|
153
|
+
node.remove_attribute('type')
|
|
154
|
+
|
|
155
|
+
if listhead_node.present?
|
|
156
|
+
format_deflist_as_table(node, labels, items, defitems)
|
|
157
|
+
else
|
|
158
|
+
format_deflist_as_dl(node, labels, items, defitems)
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def format_deflist_as_table(node, labels, items, defitems)
|
|
163
|
+
node.name = 'table'
|
|
164
|
+
node['class'] = 'table deflist'
|
|
165
|
+
listhead_node = node.at_css('listhead')
|
|
166
|
+
format_deflist_table_head(listhead_node)
|
|
167
|
+
node.at_css('thead').next = '<tbody/>'
|
|
168
|
+
labels.each { |label_node| label_node.name = 'td' }
|
|
169
|
+
items.each { |item_node| item_node.name = 'td' }
|
|
170
|
+
defitems.each do |defitem_node|
|
|
171
|
+
defitem_node.name = 'tr'
|
|
172
|
+
defitem_node.parent = node.at_css('tbody')
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def format_deflist_table_head(listhead_node)
|
|
177
|
+
listhead_node.at_css('head01').name = 'th'
|
|
178
|
+
listhead_node.at_css('head02').name = 'th'
|
|
179
|
+
listhead_node.name = 'tr'
|
|
180
|
+
listhead_node.wrap('<thead/>')
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def format_deflist_as_dl(node, labels, items, defitems)
|
|
184
|
+
node.name = 'dl'
|
|
185
|
+
node['class'] = 'deflist'
|
|
186
|
+
labels.each { |label_node| label_node.name = 'dt' }
|
|
187
|
+
items.each { |item_node| item_node.name = 'dd' }
|
|
188
|
+
defitems.each { |defitem_node| defitem_node.swap(defitem_node.children) } # unwrap
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def format_chronlists(node)
|
|
192
|
+
node.name = 'table'
|
|
193
|
+
node['class'] = 'table chronlist'
|
|
194
|
+
eventgrps = node.css('eventgrp')
|
|
195
|
+
single_events = node.css('chronitem > event')
|
|
196
|
+
multi_events = node.css('eventgrp > event')
|
|
197
|
+
format_chronlist_header(node)
|
|
198
|
+
node.at_css('thead').next = '<tbody/>'
|
|
199
|
+
format_chronlist_caption(node)
|
|
200
|
+
format_chronlist_chronitems(node)
|
|
201
|
+
format_chronlist_dates(node)
|
|
202
|
+
format_chronlist_events(eventgrps, single_events, multi_events)
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def format_chronlist_header(node)
|
|
206
|
+
node.add_child('<thead><tr><th>Date</th><th>Event</th></tr></thead>')
|
|
207
|
+
table_head = node.at_css('thead')
|
|
208
|
+
node.children.first.add_previous_sibling(table_head)
|
|
209
|
+
listhead_node = node.at_css('listhead')
|
|
210
|
+
return if listhead_node.blank?
|
|
211
|
+
|
|
212
|
+
node.at_css('thead tr th:nth-of-type(1)').content = node.at_css('listhead/head01').content
|
|
213
|
+
node.at_css('thead tr th:nth-of-type(2)').content = node.at_css('listhead/head02').content
|
|
214
|
+
listhead_node.remove
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def format_chronlist_caption(node)
|
|
218
|
+
head_node = node.at_css('head')
|
|
219
|
+
return if head_node.blank?
|
|
220
|
+
|
|
221
|
+
head_node.name = 'caption'
|
|
222
|
+
head_node['class'] = 'chronlist-head'
|
|
223
|
+
node.children.first.add_previous_sibling(head_node) # make the caption first
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def format_chronlist_chronitems(node)
|
|
227
|
+
chronitems = node.css('chronitem')
|
|
228
|
+
chronitems.each do |chronitem_node|
|
|
229
|
+
chronitem_node.name = 'tr'
|
|
230
|
+
chronitem_node.parent = node.at_css('tbody')
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def format_chronlist_dates(node)
|
|
235
|
+
dates = node.css('date')
|
|
236
|
+
dates.each do |date_node|
|
|
237
|
+
date_node.name = 'td'
|
|
238
|
+
date_node['class'] = 'chronlist-item-date'
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
def format_chronlist_events(eventgrps, single_events, multi_events)
|
|
243
|
+
eventgrps.each do |eventgrp_node|
|
|
244
|
+
eventgrp_node.name = 'td'
|
|
245
|
+
eventgrp_node['class'] = 'chronlist-item-event'
|
|
246
|
+
end
|
|
247
|
+
single_events.each do |event_node|
|
|
248
|
+
event_node.name = 'td'
|
|
249
|
+
event_node['class'] = 'chronlist-item-event'
|
|
250
|
+
end
|
|
251
|
+
multi_events.each { |event_node| event_node.name = 'div' }
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
# Format EAD <index> elements
|
|
255
|
+
def format_indexes(node)
|
|
256
|
+
index_head = node.at_css('head')
|
|
257
|
+
index_head&.name = 'h3'
|
|
258
|
+
index_head&.add_class('index-head')
|
|
259
|
+
index_head['id'] = ['index-', index_head.text].join.parameterize if index_head.present?
|
|
260
|
+
format_indexentries(node)
|
|
261
|
+
node.name = 'div'
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
# Grab all of the <indexentry> children as a nodeset, move them into
|
|
265
|
+
# a <table>, wrap each entry in a <tr> & each value in a <td>.
|
|
266
|
+
def format_indexentries(node)
|
|
267
|
+
indexentries = node.css('indexentry')
|
|
268
|
+
return if indexentries.blank?
|
|
269
|
+
|
|
270
|
+
indexentries.first.previous = '<table class="table indexentries" />'
|
|
271
|
+
indexentries.map do |i|
|
|
272
|
+
i.parent = node.at_css('table.table.indexentries')
|
|
273
|
+
i.wrap('<tr/>')
|
|
274
|
+
i.element_children.map { |c| c.wrap('<td/>') }
|
|
275
|
+
# Assuming two columns in an index, create a blank cell for entries
|
|
276
|
+
# with a missing value.
|
|
277
|
+
i.add_child('<td/>') if i.element_children.count == 1
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
# Format EAD <table> elements, converting <tgroup> to HTML <table>.
|
|
282
|
+
# Ignoring <colspec>, @colname, @colwidth complex rendering
|
|
283
|
+
# logic for now.
|
|
284
|
+
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
|
285
|
+
def format_tables(node)
|
|
286
|
+
node.remove_attribute('frame')
|
|
287
|
+
node.name = 'div' if node.css('tgroup').present?
|
|
288
|
+
format_table_head(node)
|
|
289
|
+
tgroups = node.css('tgroup')
|
|
290
|
+
tgroups&.map do |t|
|
|
291
|
+
t.name = 'table'
|
|
292
|
+
t.remove_attribute('cols')
|
|
293
|
+
t.add_class('table')
|
|
294
|
+
t.css('row').map { |r| r.name = 'tr' }
|
|
295
|
+
t.css('thead entry').map { |e| e.name = 'th' }
|
|
296
|
+
t.css('tbody entry').map { |e| e.name = 'td' }
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
|
300
|
+
|
|
301
|
+
def format_table_head(node)
|
|
302
|
+
table_head = node.at_css('head')
|
|
303
|
+
return if table_head.blank?
|
|
304
|
+
|
|
305
|
+
table_head.name = 'h3'
|
|
306
|
+
table_head.add_class('table-head')
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Arclight
|
|
4
|
+
##
|
|
5
|
+
# A module to add configuration helpers for certain fields used by Arclight
|
|
6
|
+
module FieldConfigHelpers
|
|
7
|
+
include Arclight::EadFormatHelpers
|
|
8
|
+
|
|
9
|
+
def item_requestable?(document)
|
|
10
|
+
document.requestable?
|
|
11
|
+
end
|
|
12
|
+
Arclight.deprecation.deprecate_methods(self, item_requestable?: 'Call e.g. `document.requestable?` instead')
|
|
13
|
+
|
|
14
|
+
def link_to_name_facet(args)
|
|
15
|
+
options = args[:config]&.separator_options || {}
|
|
16
|
+
values = args[:value] || []
|
|
17
|
+
|
|
18
|
+
values.map do |value|
|
|
19
|
+
link_to(
|
|
20
|
+
value,
|
|
21
|
+
search_action_path(f: { names: [value] })
|
|
22
|
+
)
|
|
23
|
+
end.to_sentence(options).html_safe
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
##
|
|
4
|
+
# Generic Helpers used in Arclight
|
|
5
|
+
module ArclightHelper
|
|
6
|
+
include Arclight::EadFormatHelpers
|
|
7
|
+
include Arclight::FieldConfigHelpers
|
|
8
|
+
include Blacklight::DocumentHelperBehavior
|
|
9
|
+
include Blacklight::LayoutHelperBehavior
|
|
10
|
+
|
|
11
|
+
def repository_collections_path(repository)
|
|
12
|
+
search_action_url(
|
|
13
|
+
f: {
|
|
14
|
+
repository: [repository.name],
|
|
15
|
+
level: ['Collection']
|
|
16
|
+
}
|
|
17
|
+
)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Returns the i18n-ed string to be used as the h1 in search results
|
|
21
|
+
def search_results_header_text
|
|
22
|
+
if (repo = repository_faceted_on).present?
|
|
23
|
+
t('arclight.search.repository_header', repository: repo.name)
|
|
24
|
+
elsif collection_active?
|
|
25
|
+
t('arclight.search.collections_header')
|
|
26
|
+
else
|
|
27
|
+
t('blacklight.search.header')
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
##
|
|
32
|
+
# Classes used for customized show page in arclight
|
|
33
|
+
def show_content_classes
|
|
34
|
+
'col-12 col-lg-8 show-document order-2'
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def show_sidebar_classes
|
|
38
|
+
'col-lg-4 order-1 collection-sidebar'
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def collection_active?
|
|
42
|
+
search_state.filter('level').values == ['Collection']
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def collection_active_class
|
|
46
|
+
'active' if collection_active?
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def grouped?
|
|
50
|
+
respond_to?(:search_state) && search_state&.params_for_search&.dig('group') == 'true'
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def search_with_group
|
|
54
|
+
search_state.params_for_search.merge('group' => 'true').except('page')
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def search_without_group
|
|
58
|
+
search_state.params_for_search.except('group', 'page')
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def on_repositories_index?
|
|
62
|
+
controller_name == 'repositories' && action_name == 'index'
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# the Repositories menu item is only active on the Repositories index page
|
|
66
|
+
def repositories_active_class
|
|
67
|
+
'active' if on_repositories_index?
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# If we have a facet on the repository, then return the Repository object for it
|
|
71
|
+
#
|
|
72
|
+
# @return [Repository]
|
|
73
|
+
def repository_faceted_on
|
|
74
|
+
repos = search_state.filter('repository').values
|
|
75
|
+
return unless repos.one?
|
|
76
|
+
|
|
77
|
+
Arclight::Repository.find_by(name: repos.first)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# determine which icon to show in search results header
|
|
81
|
+
# these icon names will need to be updated when the icons are determined
|
|
82
|
+
def document_or_parent_icon(document)
|
|
83
|
+
case document.level&.downcase
|
|
84
|
+
when 'collection'
|
|
85
|
+
'collection'
|
|
86
|
+
when 'file'
|
|
87
|
+
'file'
|
|
88
|
+
when 'series', 'subseries'
|
|
89
|
+
'folder'
|
|
90
|
+
else
|
|
91
|
+
'container'
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
##
|
|
96
|
+
# Override of BL core https://github.com/projectblacklight/blacklight/blob/v8.1.0/app/helpers/blacklight/document_helper_behavior.rb#L55
|
|
97
|
+
# Remove document_type check. It isn't a method on arclight documents
|
|
98
|
+
# Check if the document is in the user's bookmarks
|
|
99
|
+
# @param [Blacklight::Document] document
|
|
100
|
+
# @return [Boolean]
|
|
101
|
+
def bookmarked?(document)
|
|
102
|
+
current_bookmarks.any? { |x| x.document_id == document.id }
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def current_context_document
|
|
106
|
+
@document
|
|
107
|
+
end
|
|
108
|
+
end
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Arclight
|
|
4
|
+
##
|
|
5
|
+
# Model the Download links that can be configured (via YAML) for a collection
|
|
6
|
+
# or container
|
|
7
|
+
class DocumentDownloads
|
|
8
|
+
attr_reader :document
|
|
9
|
+
|
|
10
|
+
def initialize(document, id = nil)
|
|
11
|
+
@document = document
|
|
12
|
+
@id = id
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Accessor for the ID
|
|
16
|
+
# @return [String]
|
|
17
|
+
def id
|
|
18
|
+
@id || document.unitid
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Factory method for the File objects
|
|
22
|
+
# @return [Array<Arclight::DocumentDownloads::File>]
|
|
23
|
+
def files
|
|
24
|
+
data = self.class.config[id] || self.class.config['default']
|
|
25
|
+
disabled = data.delete('disabled')
|
|
26
|
+
return [] if disabled
|
|
27
|
+
|
|
28
|
+
@files ||= data.map do |file_type, file_data|
|
|
29
|
+
self.class.file_class.new(type: file_type, data: file_data, document: document)
|
|
30
|
+
end.compact
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
class << self
|
|
34
|
+
def config
|
|
35
|
+
@config ||= begin
|
|
36
|
+
YAML.safe_load_file(config_filename)
|
|
37
|
+
rescue Errno::ENOENT
|
|
38
|
+
{}
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def config_filename
|
|
43
|
+
Rails.root.join('config/downloads.yml')
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Accessor for the File Class
|
|
47
|
+
# @return [Class]
|
|
48
|
+
def file_class
|
|
49
|
+
Arclight::DocumentDownloads::File
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
##
|
|
54
|
+
# Model a single file configured in downloads.yml
|
|
55
|
+
class File
|
|
56
|
+
attr_reader :type, :document
|
|
57
|
+
|
|
58
|
+
def initialize(type:, data:, document:)
|
|
59
|
+
@type = type
|
|
60
|
+
@data = data
|
|
61
|
+
@document = document
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def href
|
|
65
|
+
return data['href'] if data['href']
|
|
66
|
+
|
|
67
|
+
format_template
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def size
|
|
71
|
+
return data['size'] if data['size']
|
|
72
|
+
|
|
73
|
+
document.public_send(data['size_accessor'].to_sym) if data['size_accessor']
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
private
|
|
77
|
+
|
|
78
|
+
attr_reader :data
|
|
79
|
+
|
|
80
|
+
def format_template
|
|
81
|
+
return unless template
|
|
82
|
+
|
|
83
|
+
template % template_interpolations
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def template
|
|
87
|
+
data['template']
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def template_interpolations
|
|
91
|
+
escaped_document_interpolations.merge(custom_interpolations).symbolize_keys
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def custom_interpolations
|
|
95
|
+
{ 'repository_id' => document.repository_config&.slug }
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def template_variables
|
|
99
|
+
template.scan(Regexp.union(/%{(\w+)}/, /%<(\w+)>/)).flatten.compact.uniq
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def escaped_document_interpolations
|
|
103
|
+
non_custom_template_variables.index_with do |method_name|
|
|
104
|
+
escape_non_url_doc_value(document.public_send(method_name))
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def escape_non_url_doc_value(value)
|
|
109
|
+
value = Array.wrap(value).first || '' # Handle single values/arrays and nil
|
|
110
|
+
return value if value.start_with?(/https?:/)
|
|
111
|
+
|
|
112
|
+
CGI.escape(value)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def non_custom_template_variables
|
|
116
|
+
template_variables.reject do |v|
|
|
117
|
+
custom_interpolations.keys.include?(v)
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Arclight
|
|
4
|
+
##
|
|
5
|
+
# Logic containing information about Solr_Ead "Parent"
|
|
6
|
+
# https://github.com/awead/solr_ead/blob/8cf7ffaa66e0e4c9c0b12f5646d6c2e20984cd99/lib/solr_ead/behaviors.rb#L54-L57
|
|
7
|
+
class Parent
|
|
8
|
+
attr_reader :id, :label, :eadid, :level
|
|
9
|
+
|
|
10
|
+
alias global_id id
|
|
11
|
+
Arclight.deprecation.deprecate_methods(self, global_id: 'Call `id` instead')
|
|
12
|
+
|
|
13
|
+
def initialize(id:, label:, eadid:, level:)
|
|
14
|
+
@id = id
|
|
15
|
+
@label = label
|
|
16
|
+
@eadid = eadid
|
|
17
|
+
@level = level
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def collection?
|
|
21
|
+
level == 'collection'
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Arclight
|
|
4
|
+
##
|
|
5
|
+
# Object for parsing and formalizing Solr_Ead "Parents"
|
|
6
|
+
# https://github.com/awead/solr_ead/blob/8cf7ffaa66e0e4c9c0b12f5646d6c2e20984cd99/lib/solr_ead/behaviors.rb#L54-L57
|
|
7
|
+
class Parents
|
|
8
|
+
attr_reader :ids, :legacy_ids, :labels, :levels
|
|
9
|
+
|
|
10
|
+
def initialize(ids:, legacy_ids:, labels:, eadid:, levels:)
|
|
11
|
+
@ids = ids
|
|
12
|
+
@legacy_ids = legacy_ids
|
|
13
|
+
@labels = labels
|
|
14
|
+
@eadid = eadid
|
|
15
|
+
@levels = levels
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def eadid
|
|
19
|
+
Arclight::NormalizedId.new(@eadid).to_s
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
##
|
|
23
|
+
# @return [Array[Arclight::Parent]]
|
|
24
|
+
def as_parents
|
|
25
|
+
(ids.presence || legacy_ids).map.with_index { |id, idx| Arclight::Parent.new(id: id, label: labels[idx], eadid: eadid, level: levels[idx]) }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
##
|
|
29
|
+
# @param [SolrDocument] document
|
|
30
|
+
def self.from_solr_document(document)
|
|
31
|
+
ids = document.parent_ids
|
|
32
|
+
legacy_ids = document.legacy_parent_ids.map { |legacy_id| document.root == legacy_id ? legacy_id : "#{document.root}#{legacy_id}" }
|
|
33
|
+
labels = document.parent_labels
|
|
34
|
+
eadid = document.eadid
|
|
35
|
+
levels = document.parent_levels
|
|
36
|
+
new(ids: ids, legacy_ids: legacy_ids, labels: labels, eadid: eadid, levels: levels)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Arclight
|
|
4
|
+
module Requests
|
|
5
|
+
##
|
|
6
|
+
# This class should be used to turn configuration into a URL and
|
|
7
|
+
# POST form specifically aimed at Aeon's external request
|
|
8
|
+
# endpoint (https://support.atlas-sys.com/hc/en-us/articles/360011820054-External-Request-Endpoint)
|
|
9
|
+
class AeonExternalRequest
|
|
10
|
+
def initialize(document, presenter)
|
|
11
|
+
@document = document
|
|
12
|
+
@presenter = presenter
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def config
|
|
16
|
+
@config ||= @document.repository_config.request_config_for_type('aeon_external_request_endpoint')
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def url
|
|
20
|
+
"#{config['request_url']}?#{url_params}"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def form_mapping
|
|
24
|
+
static_mappings.merge(dynamic_mappings)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def static_mappings
|
|
28
|
+
config['request_mappings']['static']
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def dynamic_mappings
|
|
32
|
+
config['request_mappings']['accessor'].transform_values do |v|
|
|
33
|
+
@document.public_send(v.to_sym)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def url_params
|
|
38
|
+
config['request_mappings']['url_params'].to_query
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|