iiif_print 1.0.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.
- checksums.yaml +7 -0
- data/.coveralls.yml +2 -0
- data/.env +5 -0
- data/.fcrepo_wrapper +4 -0
- data/.github/release.yml +20 -0
- data/.github/workflows/branches.yml +24 -0
- data/.github/workflows/build-lint-test-action.yaml +33 -0
- data/.github/workflows/release_labels.yml +25 -0
- data/.gitignore +52 -0
- data/.rubocop.yml +177 -0
- data/.solr_wrapper +8 -0
- data/.travis.yml +49 -0
- data/CONTRIBUTING.md +181 -0
- data/Dockerfile +15 -0
- data/Gemfile +52 -0
- data/LICENSE +203 -0
- data/README.md +203 -0
- data/Rakefile +38 -0
- data/app/actors/iiif_print/actors/file_set_actor_decorator.rb +56 -0
- data/app/assets/config/iiif_print_manifest.js +2 -0
- data/app/assets/images/iiif_print/.keep +0 -0
- data/app/assets/javascripts/iiif_print/autocomplete_fix.js +33 -0
- data/app/assets/javascripts/iiif_print/ocr_search.js.erb +6 -0
- data/app/assets/javascripts/iiif_print.js +3 -0
- data/app/assets/stylesheets/iiif_print/_iiif_print.scss +4 -0
- data/app/assets/stylesheets/iiif_print/_issue_search.scss +13 -0
- data/app/assets/stylesheets/iiif_print/_issues_calendar.scss +18 -0
- data/app/assets/stylesheets/iiif_print/_newspapers_search.scss +38 -0
- data/app/assets/stylesheets/iiif_print/_search_results.scss +6 -0
- data/app/helpers/hyrax/iiif_helper.rb +22 -0
- data/app/helpers/iiif_print/application_helper.rb +5 -0
- data/app/helpers/iiif_print_helper.rb +64 -0
- data/app/indexers/concerns/iiif_print/child_indexer.rb +34 -0
- data/app/indexers/concerns/iiif_print/file_set_indexer.rb +29 -0
- data/app/mailers/iiif_print/application_mailer.rb +8 -0
- data/app/models/concerns/iiif_print/set_child_flag.rb +29 -0
- data/app/models/concerns/iiif_print/solr/document.rb +47 -0
- data/app/models/iiif_print/application_record.rb +6 -0
- data/app/models/iiif_print/derivative_attachment.rb +8 -0
- data/app/models/iiif_print/iiif_search_response_decorator.rb +17 -0
- data/app/models/iiif_print/ingest_file_relation.rb +14 -0
- data/app/models/iiif_print/pending_relationship.rb +7 -0
- data/app/presenters/iiif_print/iiif_manifest_presenter_behavior.rb +10 -0
- data/app/presenters/iiif_print/iiif_manifest_presenter_factory_behavior.rb +33 -0
- data/app/presenters/iiif_print/work_show_presenter_decorator.rb +29 -0
- data/app/renderers/hyrax/renderers/faceted_attribute_renderer_decorator.rb +18 -0
- data/app/search_builders/concerns/iiif_print/exclude_models.rb +17 -0
- data/app/search_builders/concerns/iiif_print/highlight_search_params.rb +14 -0
- data/app/services/iiif_print/manifest_builder_service_behavior.rb +97 -0
- data/app/services/iiif_print/pluggable_derivative_service.rb +120 -0
- data/app/views/catalog/_snippets_more.html.erb +16 -0
- data/app/views/hyrax/base/_representative_media.html.erb +9 -0
- data/app/views/hyrax/base/iiif_viewers/_universal_viewer.html.erb +8 -0
- data/app/views/hyrax/file_sets/_actions.html.erb +45 -0
- data/bin/rails +13 -0
- data/config/fcrepo_wrapper_test.yml +5 -0
- data/config/initializers/assets.rb +2 -0
- data/config/locales/iiif_print.de.yml +148 -0
- data/config/locales/iiif_print.en.yml +119 -0
- data/config/locales/iiif_print.es.yml +148 -0
- data/config/locales/iiif_print.fr.yml +149 -0
- data/config/locales/iiif_print.it.yml +142 -0
- data/config/locales/iiif_print.pt-BR.yml +148 -0
- data/config/locales/iiif_print.zh.yml +142 -0
- data/config/solr_wrapper_test.yml +9 -0
- data/config/test-fixture/solr-config/_rest_managed.json +3 -0
- data/config/test-fixture/solr-config/admin-extra.html +31 -0
- data/config/test-fixture/solr-config/elevate.xml +36 -0
- data/config/test-fixture/solr-config/mapping-ISOLatin1Accent.txt +246 -0
- data/config/test-fixture/solr-config/protwords.txt +21 -0
- data/config/test-fixture/solr-config/schema.xml +366 -0
- data/config/test-fixture/solr-config/scripts.conf +24 -0
- data/config/test-fixture/solr-config/solrconfig.xml +322 -0
- data/config/test-fixture/solr-config/spellings.txt +2 -0
- data/config/test-fixture/solr-config/stopwords.txt +58 -0
- data/config/test-fixture/solr-config/stopwords_en.txt +58 -0
- data/config/test-fixture/solr-config/synonyms.txt +31 -0
- data/config/test-fixture/solr-config/xslt/example.xsl +132 -0
- data/config/test-fixture/solr-config/xslt/example_atom.xsl +67 -0
- data/config/test-fixture/solr-config/xslt/example_rss.xsl +66 -0
- data/config/test-fixture/solr-config/xslt/luke.xsl +337 -0
- data/config/vendor/fits.xml +55 -0
- data/config/vendor/imagemagick-6-policy.xml +76 -0
- data/db/migrate/20181214181358_create_iiif_print_derivative_attachments.rb +12 -0
- data/db/migrate/20190107165909_create_iiif_print_ingest_file_relations.rb +11 -0
- data/db/migrate/20230109000000_create_iiif_print_pending_relationships.rb +11 -0
- data/docker-compose.yml +129 -0
- data/iiif_print.gemspec +43 -0
- data/lib/generators/iiif_print/assets_generator.rb +29 -0
- data/lib/generators/iiif_print/catalog_controller_generator.rb +32 -0
- data/lib/generators/iiif_print/install_generator.rb +52 -0
- data/lib/generators/iiif_print/templates/config/initializers/iiif_print.rb +22 -0
- data/lib/generators/iiif_print/templates/iiif_print.scss +1 -0
- data/lib/iiif_print/base_derivative_service.rb +113 -0
- data/lib/iiif_print/blacklight_iiif_search/annotation_decorator.rb +84 -0
- data/lib/iiif_print/catalog_search_builder.rb +31 -0
- data/lib/iiif_print/configuration.rb +99 -0
- data/lib/iiif_print/data/fileset_helper.rb +25 -0
- data/lib/iiif_print/data/path_helper.rb +40 -0
- data/lib/iiif_print/data/work_derivatives.rb +323 -0
- data/lib/iiif_print/data/work_file.rb +92 -0
- data/lib/iiif_print/data/work_files.rb +199 -0
- data/lib/iiif_print/data.rb +35 -0
- data/lib/iiif_print/engine.rb +77 -0
- data/lib/iiif_print/errors.rb +9 -0
- data/lib/iiif_print/image_tool.rb +119 -0
- data/lib/iiif_print/jobs/application_job.rb +8 -0
- data/lib/iiif_print/jobs/child_works_from_pdf_job.rb +107 -0
- data/lib/iiif_print/jobs/create_relationships_job.rb +78 -0
- data/lib/iiif_print/jp2_derivative_service.rb +118 -0
- data/lib/iiif_print/jp2_image_metadata.rb +81 -0
- data/lib/iiif_print/lineage_service.rb +41 -0
- data/lib/iiif_print/metadata.rb +125 -0
- data/lib/iiif_print/pdf_derivative_service.rb +42 -0
- data/lib/iiif_print/split_pdfs/child_work_creation_from_pdf_service.rb +75 -0
- data/lib/iiif_print/split_pdfs/pages_into_images_service.rb +130 -0
- data/lib/iiif_print/split_pdfs/pdf_image_extraction_service.rb +85 -0
- data/lib/iiif_print/text_extraction/alto_reader.rb +123 -0
- data/lib/iiif_print/text_extraction/hocr_reader.rb +172 -0
- data/lib/iiif_print/text_extraction/page_ocr.rb +87 -0
- data/lib/iiif_print/text_extraction/render_alto.rb +84 -0
- data/lib/iiif_print/text_extraction/word_coords_builder.rb +38 -0
- data/lib/iiif_print/text_extraction.rb +11 -0
- data/lib/iiif_print/text_extraction_derivative_service.rb +47 -0
- data/lib/iiif_print/text_formats_from_alto_service.rb +77 -0
- data/lib/iiif_print/tiff_derivative_service.rb +50 -0
- data/lib/iiif_print/version.rb +3 -0
- data/lib/iiif_print/works_controller_behavior.rb +9 -0
- data/lib/iiif_print.rb +136 -0
- data/lib/tasks/set_child_works.rake +22 -0
- data/spec/.keep.txt +1 -0
- data/spec/factories/ability.rb +6 -0
- data/spec/factories/newspaper_issue.rb +7 -0
- data/spec/factories/newspaper_page.rb +7 -0
- data/spec/factories/newspaper_page_solr_document.rb +12 -0
- data/spec/factories/newspaper_title.rb +8 -0
- data/spec/factories/uploaded_pdf_file.rb +9 -0
- data/spec/factories/uploaded_txt_file.rb +9 -0
- data/spec/factories/user.rb +13 -0
- data/spec/fixtures/files/4.1.07.jp2 +0 -0
- data/spec/fixtures/files/4.1.07.tiff +0 -0
- data/spec/fixtures/files/README.md +7 -0
- data/spec/fixtures/files/alto-2-0.xsd +714 -0
- data/spec/fixtures/files/broken-truncated.pdf +0 -0
- data/spec/fixtures/files/credits.md +16 -0
- data/spec/fixtures/files/lowres-gray-via-ndnp-sample.tiff +0 -0
- data/spec/fixtures/files/minimal-1-page.pdf +0 -0
- data/spec/fixtures/files/minimal-2-page.pdf +0 -0
- data/spec/fixtures/files/minimal-alto.xml +31 -0
- data/spec/fixtures/files/ndnp-alto-sample.xml +24 -0
- data/spec/fixtures/files/ndnp-sample1-json.json +1 -0
- data/spec/fixtures/files/ndnp-sample1-txt.txt +1 -0
- data/spec/fixtures/files/ndnp-sample1.pdf +0 -0
- data/spec/fixtures/files/ocr_alto.xml +202 -0
- data/spec/fixtures/files/ocr_alto_scaled_4pts_per_px.xml +202 -0
- data/spec/fixtures/files/ocr_color.tiff +0 -0
- data/spec/fixtures/files/ocr_gray.jp2 +0 -0
- data/spec/fixtures/files/ocr_gray.tiff +0 -0
- data/spec/fixtures/files/ocr_mono.tiff +0 -0
- data/spec/fixtures/files/ocr_mono_text_hocr.html +78 -0
- data/spec/fixtures/files/page1.tiff +0 -0
- data/spec/fixtures/files/sample-4page-issue.pdf +0 -0
- data/spec/fixtures/files/sample-color-newsletter.pdf +0 -0
- data/spec/fixtures/files/thumbnail.jpg +0 -0
- data/spec/helpers/hyrax/iiif_helper_spec.rb +65 -0
- data/spec/helpers/iiif_print_helper_spec.rb +43 -0
- data/spec/iiif_print/base_derivative_service_spec.rb +11 -0
- data/spec/iiif_print/blacklight_iiif_search/annotation_decorator_spec.rb +51 -0
- data/spec/iiif_print/catalog_search_builder_spec.rb +60 -0
- data/spec/iiif_print/configuration_spec.rb +67 -0
- data/spec/iiif_print/data/work_derivatives_spec.rb +245 -0
- data/spec/iiif_print/data/work_file_spec.rb +99 -0
- data/spec/iiif_print/data/work_files_spec.rb +237 -0
- data/spec/iiif_print/image_tool_spec.rb +109 -0
- data/spec/iiif_print/jobs/child_works_from_pdf_job_spec.rb +30 -0
- data/spec/iiif_print/jobs/create_relationships_job_spec.rb +17 -0
- data/spec/iiif_print/jp2_image_metadata_spec.rb +37 -0
- data/spec/iiif_print/lineage_service_spec.rb +13 -0
- data/spec/iiif_print/metadata_spec.rb +115 -0
- data/spec/iiif_print/split_pdfs/pages_into_images_service_spec.rb +6 -0
- data/spec/iiif_print/text_extraction/alto_reader_spec.rb +49 -0
- data/spec/iiif_print/text_extraction/hocr_reader_spec.rb +45 -0
- data/spec/iiif_print/text_extraction/page_ocr_spec.rb +84 -0
- data/spec/iiif_print/text_extraction/render_alto_spec.rb +54 -0
- data/spec/iiif_print/text_extraction/word_coords_builder_spec.rb +44 -0
- data/spec/iiif_print_spec.rb +51 -0
- data/spec/misc_shared.rb +111 -0
- data/spec/models/iiif_print/derivative_attachment_spec.rb +37 -0
- data/spec/models/iiif_print/ingest_file_relation_spec.rb +56 -0
- data/spec/models/solr_document_spec.rb +14 -0
- data/spec/presenters/iiif_print/iiif_manifest_presenter_behavior_spec.rb +19 -0
- data/spec/presenters/iiif_print/iiif_manifest_presenter_factory_behavior_spec.rb +49 -0
- data/spec/services/iiif_print/jp2_derivative_service_spec.rb +59 -0
- data/spec/services/iiif_print/pdf_derivative_service_spec.rb +66 -0
- data/spec/services/iiif_print/pluggable_derivative_service_spec.rb +178 -0
- data/spec/services/iiif_print/text_extraction_derivative_service_spec.rb +82 -0
- data/spec/services/iiif_print/text_formats_from_alto_service_spec.rb +127 -0
- data/spec/services/iiif_print/tiff_derivative_service_spec.rb +65 -0
- data/spec/spec_helper.rb +181 -0
- data/spec/support/controller_level_helpers.rb +28 -0
- data/spec/support/iiif_print_models.rb +127 -0
- data/spec/test_app_templates/blacklight.yml +9 -0
- data/spec/test_app_templates/fedora.yml +15 -0
- data/spec/test_app_templates/lib/generators/test_app_generator.rb +40 -0
- data/spec/test_app_templates/redis.yml +9 -0
- data/spec/test_app_templates/solr/conf/schema.xml +362 -0
- data/spec/test_app_templates/solr/conf/solrconfig.xml +322 -0
- data/spec/test_app_templates/solr.yml +7 -0
- data/tasks/iiif_print_dev.rake +34 -0
- data/tmp/.keep +0 -0
- metadata +605 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
module IiifPrintHelper
|
|
2
|
+
##
|
|
3
|
+
# create link anchor to be read by UniversalViewer
|
|
4
|
+
# in order to show keyword search
|
|
5
|
+
# @param query_params_hash [Hash] current_search_session.query_params
|
|
6
|
+
# @return [String] or [nil] anchor
|
|
7
|
+
def iiif_search_anchor(query_params_hash)
|
|
8
|
+
query = search_query(query_params_hash)
|
|
9
|
+
return nil if query.blank?
|
|
10
|
+
"?h=#{query}"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
##
|
|
14
|
+
# get the query, which may be in a different object,
|
|
15
|
+
# depending if regular search or newspapers_search was run
|
|
16
|
+
# @param query_params_hash [Hash] current_search_session.query_params
|
|
17
|
+
# @return [String] or [nil] query
|
|
18
|
+
def search_query(query_params_hash)
|
|
19
|
+
query_params_hash[:q] || query_params_hash[:all_fields]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
##
|
|
23
|
+
# return the matching highlighted terms from Solr highlight field
|
|
24
|
+
#
|
|
25
|
+
# @param document [SolrDocument]
|
|
26
|
+
# @param hl_fl [String] the name of the Solr field with highlights
|
|
27
|
+
# @param hl_tag [String] the HTML element name used for marking highlights
|
|
28
|
+
# configured in Solr as hl.tag.pre value
|
|
29
|
+
# @return [String]
|
|
30
|
+
def highlight_matches(document, hl_fl, hl_tag)
|
|
31
|
+
hl_matches = []
|
|
32
|
+
# regex: find all chars between hl_tag, but NOT other <element>
|
|
33
|
+
regex = /<#{hl_tag}>[^<>]+<\/#{hl_tag}>/
|
|
34
|
+
hls = document.highlight_field(hl_fl)
|
|
35
|
+
return nil if hls.blank?
|
|
36
|
+
hls.each do |hl|
|
|
37
|
+
matches = hl.scan(regex)
|
|
38
|
+
matches.each do |match|
|
|
39
|
+
hl_matches << match.gsub(/<[\/]*#{hl_tag}>/, '').downcase
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
hl_matches.uniq.sort.join(' ')
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
##
|
|
46
|
+
# print the ocr snippets. if more than one, separate with <br/>
|
|
47
|
+
#
|
|
48
|
+
# @param options [Hash] options hash provided by Blacklight
|
|
49
|
+
# @return [String] snippets HTML to be rendered
|
|
50
|
+
# rubocop:disable Rails/OutputSafety
|
|
51
|
+
def render_ocr_snippets(options = {})
|
|
52
|
+
snippets = options[:value]
|
|
53
|
+
snippets_content = [content_tag('div',
|
|
54
|
+
"... #{snippets.first} ...".html_safe,
|
|
55
|
+
class: 'ocr_snippet first_snippet')]
|
|
56
|
+
if snippets.length > 1
|
|
57
|
+
snippets_content << render(partial: 'catalog/snippets_more',
|
|
58
|
+
locals: { snippets: snippets.drop(1),
|
|
59
|
+
options: options })
|
|
60
|
+
end
|
|
61
|
+
snippets_content.join("\n").html_safe
|
|
62
|
+
end
|
|
63
|
+
# rubocop:enable Rails/OutputSafety
|
|
64
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module IiifPrint
|
|
4
|
+
module ChildIndexer
|
|
5
|
+
##
|
|
6
|
+
# @api private
|
|
7
|
+
#
|
|
8
|
+
# The goal of this method is to encapsulate the logic for what all we need for child
|
|
9
|
+
# relationships.
|
|
10
|
+
def self.decorate_work_types!
|
|
11
|
+
# TODO: This method is in the wrong location; says indexing but there's also the SetChildFlag
|
|
12
|
+
# consideration. Consider refactoring this stuff into a single nested module.
|
|
13
|
+
#
|
|
14
|
+
|
|
15
|
+
Hyrax.config.curation_concerns.each do |work_type|
|
|
16
|
+
work_type.send(:include, IiifPrint::SetChildFlag) unless work_type.included_modules.include?(IiifPrint::SetChildFlag)
|
|
17
|
+
indexer = work_type.indexer
|
|
18
|
+
unless indexer.respond_to?(:iiif_print_lineage_service)
|
|
19
|
+
indexer.prepend(self)
|
|
20
|
+
indexer.class_attribute(:iiif_print_lineage_service, default: IiifPrint::LineageService)
|
|
21
|
+
end
|
|
22
|
+
work_type::GeneratedResourceSchema.send(:include, IiifPrint::SetChildFlag)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def generate_solr_document
|
|
27
|
+
super.tap do |solr_doc|
|
|
28
|
+
solr_doc['is_child_bsi'] = object.is_child
|
|
29
|
+
solr_doc['is_page_of_ssim'] = iiif_print_lineage_service.ancestor_ids_for(object)
|
|
30
|
+
solr_doc['file_set_ids_ssim'] = iiif_print_lineage_service.descendent_file_set_ids_for(object)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module IiifPrint
|
|
4
|
+
module FileSetIndexer
|
|
5
|
+
# Why `.decorate`? In my tests for Rails 5.2, I'm not able to use the prepended nor included
|
|
6
|
+
# blocks to assign a class_attribute when I "prepend" a module to the base class. This method
|
|
7
|
+
# allows me to handle that behavior.
|
|
8
|
+
#
|
|
9
|
+
# @param base [Class]
|
|
10
|
+
# @return [Class] the given base, now decorated in all of it's glory
|
|
11
|
+
def self.decorate(base)
|
|
12
|
+
base.prepend(self)
|
|
13
|
+
base.class_attribute :iiif_print_lineage_service, default: IiifPrint::LineageService
|
|
14
|
+
base
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def generate_solr_document
|
|
18
|
+
super.tap do |solr_doc|
|
|
19
|
+
# only UV viewable images should have is_page_of, it is only used for iiif search
|
|
20
|
+
solr_doc['is_page_of_ssim'] = iiif_print_lineage_service.ancestor_ids_for(object) if object.mime_type&.match(/image/)
|
|
21
|
+
# index for full text search
|
|
22
|
+
text = IiifPrint::Data::WorkDerivatives.data(from: object, of_type: 'txt')
|
|
23
|
+
text = text.tr("\n", ' ').squeeze(' ')
|
|
24
|
+
solr_doc['all_text_timv'] = text
|
|
25
|
+
solr_doc['all_text_tsimv'] = text
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RDF
|
|
4
|
+
class CustomIsChildTerm < Vocabulary('http://id.loc.gov/vocabulary/identifiers/')
|
|
5
|
+
property 'is_child'
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
module IiifPrint
|
|
10
|
+
module SetChildFlag
|
|
11
|
+
extend ActiveSupport::Concern
|
|
12
|
+
included do
|
|
13
|
+
# Why the try? A work type's GeneratedResourceSchema goes through this path as well
|
|
14
|
+
# and does not have an #after_save resulting in a NoMethodError.
|
|
15
|
+
try(:after_save, :set_children)
|
|
16
|
+
property :is_child,
|
|
17
|
+
predicate: ::RDF::CustomIsChildTerm.is_child,
|
|
18
|
+
multiple: false do |index|
|
|
19
|
+
index.as :stored_searchable
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def set_children
|
|
24
|
+
ordered_works.each do |child_work|
|
|
25
|
+
child_work.update(is_child: true) unless child_work.is_child
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
module IiifPrint::Solr::Document
|
|
2
|
+
# @note Why decorate? We want to avoid including this module via generator. And the generator
|
|
3
|
+
# previously did two things: 1) include `IiifPrint::Solr::Document` in `SolrDocument`; 2)
|
|
4
|
+
# add the `attribute :is_child` field to the SolrDocument. We can't rely on `included do`
|
|
5
|
+
# block to handle that.
|
|
6
|
+
#
|
|
7
|
+
# This method is responsible for configuring the SolrDocument for a Hyrax/Hyku application. It
|
|
8
|
+
# does three things:
|
|
9
|
+
#
|
|
10
|
+
# 1. Adds instance methods to the SolrDocument (see implementation below)
|
|
11
|
+
# 2. Adds the `is_child` attribute to the SolrDocument
|
|
12
|
+
# 3. Adds a class attribute (e.g. `iiif_print_solr_field_names`) to allow further customization.
|
|
13
|
+
#
|
|
14
|
+
# @note These `iiif_print_solr_field_names` came from the newspaper_works implementation and are
|
|
15
|
+
# carried forward without much consideration, except to say "Make it configurable!"
|
|
16
|
+
#
|
|
17
|
+
# @param base [Class<SolrDocument>]
|
|
18
|
+
# @return [Class<SolrDocument>]
|
|
19
|
+
def self.decorate(base)
|
|
20
|
+
base.prepend(self)
|
|
21
|
+
base.send(:attribute, :is_child, Hyrax::SolrDocument::Metadata::Solr::String, 'is_child_bsi')
|
|
22
|
+
|
|
23
|
+
# @note These properties came from the newspaper_works gem. They are configurable.
|
|
24
|
+
base.class_attribute :iiif_print_solr_field_names, default: %w[alternative_title genre
|
|
25
|
+
issn lccn oclcnum held_by text_direction
|
|
26
|
+
page_number section author photographer
|
|
27
|
+
volume issue_number geographic_coverage
|
|
28
|
+
extent publication_date height width
|
|
29
|
+
edition_number edition_name frequency preceded_by
|
|
30
|
+
succeeded_by]
|
|
31
|
+
base
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def method_missing(method_name, *args, &block)
|
|
35
|
+
super unless iiif_print_solr_field_names.include? method_name.to_s
|
|
36
|
+
self[::ActiveFedora.index_field_mapper.solr_name(method_name.to_s)]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def respond_to_missing?(method_name, include_private = false)
|
|
40
|
+
iiif_print_solr_field_names.include?(method_name.to_s) || super
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# TODO: consider configuring this field name; we use the magic field in lots of places.
|
|
44
|
+
def file_set_ids
|
|
45
|
+
self['file_set_ids_ssim']
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
module IiifPrint
|
|
2
|
+
class DerivativeAttachment < ApplicationRecord
|
|
3
|
+
# We can store nil/optional fileset as interim value before fileset
|
|
4
|
+
# construction, but we require at minimum, path, destination_name
|
|
5
|
+
validates :path, presence: true
|
|
6
|
+
validates :destination_name, presence: true
|
|
7
|
+
end
|
|
8
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module IiifPrint
|
|
2
|
+
module IiifSearchResponseDecorator
|
|
3
|
+
# Enable the user to search for child metadata in the parent's UV
|
|
4
|
+
# @see https://github.com/scientist-softserv/louisville-hyku/commit/67467e5cf9fdb755f54419f17d3c24c87032d0af
|
|
5
|
+
def annotation_list
|
|
6
|
+
json_results = super
|
|
7
|
+
json_results&.[]('resources')&.each do |result_hit|
|
|
8
|
+
next if result_hit['resource'].present?
|
|
9
|
+
result_hit['resource'] = {
|
|
10
|
+
"@type": "cnt:ContentAsText",
|
|
11
|
+
"chars": "Metadata match, see sidebar for details"
|
|
12
|
+
}
|
|
13
|
+
end
|
|
14
|
+
json_results
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module IiifPrint
|
|
2
|
+
class IngestFileRelation < ApplicationRecord
|
|
3
|
+
validates :file_path, presence: true
|
|
4
|
+
validates :derivative_path, presence: true
|
|
5
|
+
|
|
6
|
+
# Query by file path for all derivatives, as de-duplicated array of
|
|
7
|
+
# derivative paths.
|
|
8
|
+
# @param path [String] Path to primary file
|
|
9
|
+
# @return [Array<String>] de-duplicated array of derivative paths.
|
|
10
|
+
def self.derivatives_for_file(path)
|
|
11
|
+
where(file_path: path).pluck(:derivative_path).uniq
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# mixin to provide URL for IIIF Content Search service
|
|
2
|
+
module IiifPrint
|
|
3
|
+
module IiifManifestPresenterBehavior
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
|
|
6
|
+
def search_service
|
|
7
|
+
Rails.application.routes.url_helpers.solr_document_iiif_search_url(id, host: hostname)
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module IiifPrint
|
|
2
|
+
module IiifManifestPresenterFactoryBehavior
|
|
3
|
+
# This will override Hyrax::IiifManifestPresenter::Factory#build and introducing
|
|
4
|
+
# the expected behavior:
|
|
5
|
+
# - child work images show as canvases in the parent work manifest
|
|
6
|
+
# - child work images show in the uv on the parent show page
|
|
7
|
+
# - still create the manifest if the parent work has images attached but the child works do not
|
|
8
|
+
def build
|
|
9
|
+
ids.map do |id|
|
|
10
|
+
solr_doc = load_docs.find { |doc| doc.id == id }
|
|
11
|
+
next unless solr_doc
|
|
12
|
+
|
|
13
|
+
if solr_doc.file_set?
|
|
14
|
+
presenter_class.for(solr_doc)
|
|
15
|
+
elsif Hyrax.config.curation_concerns.include?(solr_doc.hydra_model)
|
|
16
|
+
# look up file set ids and loop through those
|
|
17
|
+
file_set_docs = load_file_set_docs(solr_doc.file_set_ids)
|
|
18
|
+
file_set_docs.map { |doc| presenter_class.for(doc) } if file_set_docs.length
|
|
19
|
+
end
|
|
20
|
+
end.flatten.compact
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
# still create the manifest if the parent work has images attached but the child works do not
|
|
26
|
+
def load_file_set_docs(file_set_ids)
|
|
27
|
+
return [] if file_set_ids.nil?
|
|
28
|
+
|
|
29
|
+
query("{!terms f=id}#{file_set_ids.join(',')}", rows: 1000)
|
|
30
|
+
.map { |res| ::SolrDocument.new(res) }
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module IiifPrint
|
|
4
|
+
module WorkShowPresenterDecorator
|
|
5
|
+
delegate :file_set_ids, to: :solr_document
|
|
6
|
+
|
|
7
|
+
# OVERRIDE Hyrax 2.9.6 to remove check for representative_presenter.image? and allow
|
|
8
|
+
# a fallback to check for images on the child works
|
|
9
|
+
# @return [Boolean] render a IIIF viewer
|
|
10
|
+
def iiif_viewer?
|
|
11
|
+
parent_work_has_files? || child_work_has_files?
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
alias universal_viewer? iiif_viewer?
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def parent_work_has_files?
|
|
19
|
+
Hyrax.config.iiif_image_server? &&
|
|
20
|
+
representative_id.present? &&
|
|
21
|
+
representative_presenter.present? &&
|
|
22
|
+
members_include_viewable_image?
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def child_work_has_files?
|
|
26
|
+
file_set_ids.present?
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# OVERRIDE Hyrax 2.9.6 to give user ability to display child works form linked facets
|
|
4
|
+
# We did work to display only parent works by default, for this client
|
|
5
|
+
module Hyrax
|
|
6
|
+
module Renderers
|
|
7
|
+
module FacetedAttributeRendererDecorator
|
|
8
|
+
private
|
|
9
|
+
|
|
10
|
+
# OVERRIDE Hyrax 2.9.6 to give user ability to display child works form linked facets
|
|
11
|
+
def search_path(value)
|
|
12
|
+
path = super(value)
|
|
13
|
+
path += '&include_child_works=true' if options[:is_child_bsi] == true
|
|
14
|
+
path
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module IiifPrint
|
|
2
|
+
# hide Title, Container, and Issue objects if this is a keyword search
|
|
3
|
+
# can be added to default_processor_chain in a SearchBuilder class
|
|
4
|
+
module ExcludeModels
|
|
5
|
+
extend ActiveSupport::Concern
|
|
6
|
+
|
|
7
|
+
def exclude_models(solr_parameters, config: IiifPrint.config)
|
|
8
|
+
return unless solr_parameters[:q] || solr_parameters[:all_fields]
|
|
9
|
+
|
|
10
|
+
solr_parameters[:fq] ||= []
|
|
11
|
+
key = config.excluded_model_name_solr_field_key
|
|
12
|
+
config.excluded_model_name_solr_field_values.each do |value|
|
|
13
|
+
solr_parameters[:fq] << "-#{key}:\"#{value}\""
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module IiifPrint
|
|
2
|
+
# add highlighting on _stored_ full text field if this is a keyword search
|
|
3
|
+
# can be added to default_processor_chain in a SearchBuilder class
|
|
4
|
+
module HighlightSearchParams
|
|
5
|
+
# add highlights on full text field, if there is a keyword query
|
|
6
|
+
def highlight_search_params(solr_parameters = {})
|
|
7
|
+
return unless solr_parameters[:q] || solr_parameters[:all_fields]
|
|
8
|
+
solr_parameters[:hl] = true
|
|
9
|
+
solr_parameters[:'hl.fl'] = 'all_text_tsimv'
|
|
10
|
+
solr_parameters[:'hl.fragsize'] = 100
|
|
11
|
+
solr_parameters[:'hl.snippets'] = 5
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
module IiifPrint
|
|
2
|
+
module ManifestBuilderServiceBehavior
|
|
3
|
+
def initialize(*args,
|
|
4
|
+
version: IiifPrint.config.default_iiif_manifest_version,
|
|
5
|
+
iiif_manifest_factory: iiif_manifest_factory_for(version),
|
|
6
|
+
&block)
|
|
7
|
+
super(*args, iiif_manifest_factory: iiif_manifest_factory, &block)
|
|
8
|
+
@version = version.to_i
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def manifest_for(presenter:)
|
|
12
|
+
build_manifest(presenter: presenter)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
VERSION_TO_MANIFEST_FACTORY_MAP = {
|
|
18
|
+
2 => ::IIIFManifest::ManifestFactory,
|
|
19
|
+
3 => ::IIIFManifest::V3::ManifestFactory
|
|
20
|
+
}.freeze
|
|
21
|
+
|
|
22
|
+
def iiif_manifest_factory_for(version)
|
|
23
|
+
VERSION_TO_MANIFEST_FACTORY_MAP.fetch(version.to_i)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
##
|
|
27
|
+
# Allows for the display of metadata for child works in UV
|
|
28
|
+
#
|
|
29
|
+
# @see https://github.com/samvera/hyrax/blob/main/app/services/hyrax/manifest_builder_service.rb
|
|
30
|
+
def build_manifest(presenter:)
|
|
31
|
+
# ::IIIFManifest::ManifestBuilder#to_h returns a
|
|
32
|
+
# IIIFManifest::ManifestBuilder::IIIFManifest, not a Hash.
|
|
33
|
+
# to get a Hash, we have to call its #to_json, then parse.
|
|
34
|
+
#
|
|
35
|
+
# wild times. maybe there's a better way to do this with the
|
|
36
|
+
# ManifestFactory interface?
|
|
37
|
+
manifest = manifest_factory.new(presenter).to_h
|
|
38
|
+
hash = JSON.parse(manifest.to_json)
|
|
39
|
+
hash = send("sanitize_v#{@version}", hash: hash, presenter: presenter)
|
|
40
|
+
send("sorted_canvases_v#{@version}", hash: hash, sort_field: IiifPrint.config.sort_iiif_manifest_canvases_by)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def sanitize_v2(hash:, presenter:)
|
|
44
|
+
hash['label'] = CGI.unescapeHTML(sanitize_value(hash['label'])) if hash.key?('label')
|
|
45
|
+
hash.delete('description') # removes default description since it's in the metadata fields
|
|
46
|
+
hash['sequences']&.each do |sequence|
|
|
47
|
+
sequence['canvases']&.each do |canvas|
|
|
48
|
+
canvas['label'] = CGI.unescapeHTML(sanitize_value(canvas['label']))
|
|
49
|
+
apply_v2_metadata_to_canvas(canvas: canvas, presenter: presenter)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
hash
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def sanitize_v3(hash:, **)
|
|
56
|
+
# TODO: flesh out metadata for v3
|
|
57
|
+
hash
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def apply_v2_metadata_to_canvas(canvas:, presenter:)
|
|
61
|
+
solr_docs = get_solr_docs(presenter)
|
|
62
|
+
# uses the '@id' property which is a URL that contains the FileSet id
|
|
63
|
+
file_set_id = canvas['@id'].split('/').last
|
|
64
|
+
# finds the image that the FileSet is attached to and creates metadata on that canvas
|
|
65
|
+
image = solr_docs.find { |doc| doc[:member_ids_ssim]&.include?(file_set_id) }
|
|
66
|
+
canvas_metadata = IiifPrint.manifest_metadata_for(work: image,
|
|
67
|
+
current_ability: presenter.ability,
|
|
68
|
+
base_url: presenter.base_url)
|
|
69
|
+
canvas['metadata'] = canvas_metadata
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def sorted_canvases_v2(hash:, sort_field:)
|
|
73
|
+
sort_field = Hyrax::Renderers::AttributeRenderer.new(sort_field, nil).label
|
|
74
|
+
hash["sequences"]&.first&.[]("canvases")&.sort_by! do |canvas|
|
|
75
|
+
selection = canvas["metadata"].select { |h| h["label"] == sort_field }
|
|
76
|
+
fallback = [{ label: sort_field, value: ['~'] }]
|
|
77
|
+
identifier_metadata = selection.presence || fallback
|
|
78
|
+
identifier_metadata.first["value"] if identifier_metadata.present?
|
|
79
|
+
end
|
|
80
|
+
hash
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def sorted_canvases_v3(hash:, **)
|
|
84
|
+
# TODO: flesh out metadata for v3
|
|
85
|
+
hash
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def get_solr_docs(presenter)
|
|
89
|
+
parent_id = [presenter._source['id']]
|
|
90
|
+
child_ids = presenter._source['member_ids_ssim']
|
|
91
|
+
parent_id_and_child_ids = parent_id + child_ids
|
|
92
|
+
query = ActiveFedora::SolrQueryBuilder.construct_query_for_ids(parent_id_and_child_ids)
|
|
93
|
+
solr_hits = ActiveFedora::SolrService.query(query, fq: "-has_model_ssim:FileSet", rows: 100_000)
|
|
94
|
+
solr_hits.map { |solr_hit| ::SolrDocument.new(solr_hit) }
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# General derivative service for IiifPrint, which is meant to wrap
|
|
2
|
+
# and replace the stock Hyrax::FileSetDerivativeService with a proxy
|
|
3
|
+
# that runs one or more derivative service "plugin" components.
|
|
4
|
+
#
|
|
5
|
+
# Note: Hyrax::DerivativeService consumes this, instead of (directly)
|
|
6
|
+
# consuming Hyrax::FileSetDerivativeService.
|
|
7
|
+
#
|
|
8
|
+
# Unlike the "run the first valid plugin" arrangement that the
|
|
9
|
+
# Hyrax::DerivativeService uses to run an actual derivative creation
|
|
10
|
+
# service component, this component is:
|
|
11
|
+
#
|
|
12
|
+
# (a) Consumed by Hyrax::DerivativeService as that first valid plugin;
|
|
13
|
+
#
|
|
14
|
+
# (b) Wraps and runs 0..* plugins, not just the first.
|
|
15
|
+
#
|
|
16
|
+
# This should be registered to take precedence over default by:
|
|
17
|
+
# Hyrax::DerivativeService.services.unshift(
|
|
18
|
+
# IiifPrint::PluggableDerivativeService
|
|
19
|
+
# )
|
|
20
|
+
#
|
|
21
|
+
# Modify IiifPrint::PluggableDerivativeService.plugins
|
|
22
|
+
# to add, remove, or reorder plugin (derivative service) classes.
|
|
23
|
+
#
|
|
24
|
+
class IiifPrint::PluggableDerivativeService
|
|
25
|
+
class_attribute :allowed_methods, default: [:cleanup_derivatives, :create_derivatives]
|
|
26
|
+
class_attribute :default_plugins, default: [Hyrax::FileSetDerivativesService]
|
|
27
|
+
class_attribute :derivative_path_factory, default: Hyrax::DerivativePath
|
|
28
|
+
|
|
29
|
+
def initialize(file_set, plugins: plugins_for(file_set))
|
|
30
|
+
@file_set = file_set
|
|
31
|
+
@plugins = Array.wrap(plugins)
|
|
32
|
+
@valid_plugins = plugins.map { |plugin| plugin.new(file_set) }.select(&:valid?)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
attr_reader :file_set, :plugins, :valid_plugins
|
|
36
|
+
delegate :uri, :mime_type, to: :file_set
|
|
37
|
+
|
|
38
|
+
# this wrapper/proxy/composite is always valid, but it may compose
|
|
39
|
+
# multiple plugins, some of which may or may not be valid, so
|
|
40
|
+
# validity checks happen within as well.
|
|
41
|
+
def valid?
|
|
42
|
+
!valid_plugins.size.zero?
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# get derivative services relevant to method name and file_set context
|
|
46
|
+
# -- omits plugins if particular destination exists or will soon.
|
|
47
|
+
def services(method_name)
|
|
48
|
+
valid_plugins.select do |plugin|
|
|
49
|
+
dest = nil
|
|
50
|
+
dest = plugin.target_extension if plugin.respond_to?(:target_extension)
|
|
51
|
+
!skip_destination?(method_name, dest)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
def respond_to_missing?(method_name, include_private = false)
|
|
58
|
+
allowed_methods.include?(method_name) || super
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def method_missing(method_name, *args, **opts, &block)
|
|
62
|
+
if allowed_methods.include?(method_name)
|
|
63
|
+
# we have an allowed method, construct services and include all valid
|
|
64
|
+
# services for the file_set
|
|
65
|
+
# services = plugins.map { |plugin| plugin.new(file_set) }.select(&:valid?)
|
|
66
|
+
# run all valid services, in order:
|
|
67
|
+
services(method_name).each do |plugin|
|
|
68
|
+
plugin.send(method_name, *args, **opts, &block)
|
|
69
|
+
end
|
|
70
|
+
else
|
|
71
|
+
super
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def skip_destination?(method_name, destination_name)
|
|
76
|
+
return false unless method_name == :create_derivatives
|
|
77
|
+
return false unless destination_name
|
|
78
|
+
# NOTE: What are we after with this nil test? Are we looking for persisted objects?
|
|
79
|
+
return false if file_set.id.nil?
|
|
80
|
+
|
|
81
|
+
# skip :create_derivatives if existing --> do not re-create
|
|
82
|
+
existing_derivative?(destination_name) ||
|
|
83
|
+
impending_derivative?(destination_name)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def existing_derivative?(name)
|
|
87
|
+
path = derivative_path_factory.derivative_path_for_reference(
|
|
88
|
+
file_set,
|
|
89
|
+
name
|
|
90
|
+
)
|
|
91
|
+
File.exist?(path)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# is there an impending attachment from ingest logged to db?
|
|
95
|
+
# -- avoids stomping over pre-made derivative
|
|
96
|
+
# for which an attachment is still in-progress.
|
|
97
|
+
def impending_derivative?(name)
|
|
98
|
+
IiifPrint::DerivativeAttachment.exists?(
|
|
99
|
+
fileset_id: file_set.id,
|
|
100
|
+
destination_name: name
|
|
101
|
+
)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# This method is responsible for determine what are the possible plugins / services that this file
|
|
105
|
+
# set would use. That "possibility" is based on the work. Later, we will check the plugin's
|
|
106
|
+
# "valid?" which would now look at the specific file_set for validity.
|
|
107
|
+
def plugins_for(file_set)
|
|
108
|
+
parent = parent_for(file_set)
|
|
109
|
+
return Array(default_plugins) if parent.nil?
|
|
110
|
+
return Array(default_plugins) unless parent.respond_to?(:iiif_print_config)
|
|
111
|
+
|
|
112
|
+
(file_set.parent.iiif_print_config.derivative_service_plugins + Array(default_plugins)).flatten.compact.uniq
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def parent_for(file_set)
|
|
116
|
+
# fallback to Fedora-stored relationships if work's aggregation of
|
|
117
|
+
# file set is not indexed in Solr
|
|
118
|
+
file_set.parent || file_set.member_of.find(&:work?)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<%# additional ocr snippets, with a Bootstrap collapse toggle control %>
|
|
2
|
+
<% document_id = options[:document].id %>
|
|
3
|
+
<div class="collapse ocr_snippet" id="<%= "snippet_collapse_#{document_id}" %>">
|
|
4
|
+
<% snippets.each do |snippet| %>
|
|
5
|
+
<%= content_tag('div',
|
|
6
|
+
"... #{snippet} ...".html_safe,
|
|
7
|
+
class: 'ocr_snippet') %>
|
|
8
|
+
<% end %>
|
|
9
|
+
</div>
|
|
10
|
+
<%= link_to(t('blacklight.search.results.snippets.more'),
|
|
11
|
+
"#snippet_collapse_#{document_id}",
|
|
12
|
+
data: {toggle: 'collapse'},
|
|
13
|
+
'aria-expanded' => 'false',
|
|
14
|
+
'aria-controls' => "#snippet_collapse_#{document_id}",
|
|
15
|
+
class: 'ocr_snippets_expand js-controls')
|
|
16
|
+
%>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<% if presenter.iiif_viewer? %>
|
|
2
|
+
<% if defined?(viewer) && viewer %>
|
|
3
|
+
<%= iiif_viewer_display presenter %>
|
|
4
|
+
<% else %>
|
|
5
|
+
<%= render media_display_partial(presenter.representative_presenter), file_set: presenter.representative_presenter %>
|
|
6
|
+
<% end %>
|
|
7
|
+
<% else %>
|
|
8
|
+
<%= image_tag 'default.png', class: "canonical-image", alt: 'default representative image' %>
|
|
9
|
+
<% end %>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<div class="viewer-wrapper">
|
|
2
|
+
<iframe
|
|
3
|
+
id="uv-iframe"
|
|
4
|
+
src="<%= universal_viewer_base_url %>#?manifest=<%= main_app.polymorphic_url [main_app, :manifest, presenter], { locale: nil } %>&config=<%= universal_viewer_config_url %>"
|
|
5
|
+
allowfullscreen="true"
|
|
6
|
+
frameborder="0"
|
|
7
|
+
></iframe>
|
|
8
|
+
</div>
|