iiif_print 3.1.2 → 3.2.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 +4 -4
- data/Gemfile.lock +2 -1
- data/iiif_print.gemspec +1 -0
- data/lib/iiif_print/configuration.rb +3 -1
- data/lib/iiif_print/engine.rb +1 -0
- data/lib/iiif_print/flexibility/fields.rb +66 -0
- data/lib/iiif_print/flexibility/values.rb +148 -0
- data/lib/iiif_print/flexibility.rb +64 -0
- data/lib/iiif_print/metadata.rb +20 -3
- data/lib/iiif_print/version.rb +1 -1
- data/lib/iiif_print.rb +24 -4
- metadata +18 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 01fd18bb505838305103b589e56d196fbc346eb00390de671c53bb15083a39d6
|
|
4
|
+
data.tar.gz: c7bf87ae11b5ae00b597076254d897c9519fc2bf9facd777763861dcca511adf
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3eee1a13ecdf5693e0dd987a9331d527fcf884d0c8dc10ea12b14f7b99165a3f13b712ac5cfddb6d1579fbd33ce6fc0945c1bc2c3195ff1aff7c56637e3aee46
|
|
7
|
+
data.tar.gz: 1a85675fa01612c0fc9115e2f1cf524fae745d6a2c4b8b897b283c4272bd1583ef3c40e5e9b605591cc36a641a4f8aedb8c5b022a90534bbb31f725aa670e8be
|
data/Gemfile.lock
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: /app/samvera/hyrax-webapp
|
|
3
3
|
specs:
|
|
4
|
-
iiif_print (3.
|
|
4
|
+
iiif_print (3.2.0)
|
|
5
5
|
blacklight_iiif_search (>= 1.0, < 3.0)
|
|
6
6
|
derivative-rodeo (~> 0.5)
|
|
7
7
|
hyrax (>= 2.5, < 6)
|
|
8
8
|
nokogiri (>= 1.13.2)
|
|
9
9
|
rdf-vocab (~> 3.0)
|
|
10
|
+
request_store (>= 1.0)
|
|
10
11
|
|
|
11
12
|
GEM
|
|
12
13
|
remote: https://rubygems.org/
|
data/iiif_print.gemspec
CHANGED
|
@@ -25,6 +25,7 @@ SUMMARY
|
|
|
25
25
|
spec.add_dependency 'hyrax', '>= 2.5', '< 6'
|
|
26
26
|
spec.add_dependency 'nokogiri', '>=1.13.2'
|
|
27
27
|
spec.add_dependency 'rdf-vocab', '~> 3.0'
|
|
28
|
+
spec.add_dependency 'request_store', '>= 1.0'
|
|
28
29
|
|
|
29
30
|
spec.add_development_dependency 'bixby'
|
|
30
31
|
spec.add_development_dependency 'database_cleaner', '~> 1.3'
|
|
@@ -289,9 +289,11 @@ module IiifPrint
|
|
|
289
289
|
##
|
|
290
290
|
# This is the default sorter for the metadata. It will sort by the order of the keys specificied.
|
|
291
291
|
# By default, this is turned off as it returns nil. If you want to turn it on, you can set this
|
|
292
|
-
#
|
|
292
|
+
# to an array of symbols for the properties on the work. Properties not listed follow the listed
|
|
293
|
+
# ones, or take the place of `:remaining` when it is listed.
|
|
293
294
|
#
|
|
294
295
|
# @example [:title, :description, :date_created]
|
|
296
|
+
# @example [:title, :collection, :remaining, :rights_statement]
|
|
295
297
|
# @return [Array<Symbol>]
|
|
296
298
|
def iiif_metadata_field_presentation_order
|
|
297
299
|
@iiif_metadata_field_presentation_order || nil
|
data/lib/iiif_print/engine.rb
CHANGED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module IiifPrint
|
|
4
|
+
module Flexibility
|
|
5
|
+
##
|
|
6
|
+
# The fields a flexible record's show page lists, from its M3 profile: those an anonymous visitor may see and
|
|
7
|
+
# its show presenter can render, labeled and ordered as the profile says, plus its collections. Each carries
|
|
8
|
+
# its view options, which {IiifPrint::Flexibility::Values} renders it by.
|
|
9
|
+
class Fields
|
|
10
|
+
# The show page leads with the title and description, then the work's collections.
|
|
11
|
+
DEFAULT_ORDER = %i[title description abstract collection remaining].freeze
|
|
12
|
+
|
|
13
|
+
# @param document [SolrDocument]
|
|
14
|
+
# @param ability [Ability]
|
|
15
|
+
# @param sort_order [Array<Symbol>] see {IiifPrint::Configuration#iiif_metadata_field_presentation_order};
|
|
16
|
+
# {DEFAULT_ORDER} when unset
|
|
17
|
+
def initialize(document, ability, sort_order: IiifPrint.config.iiif_metadata_field_presentation_order)
|
|
18
|
+
@document = document
|
|
19
|
+
@ability = ability
|
|
20
|
+
@sort_order = sort_order || DEFAULT_ORDER
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# @return [Array<IiifPrint::Field>]
|
|
24
|
+
def to_a
|
|
25
|
+
presenter = Flexibility.presenter_for(@document, @ability)
|
|
26
|
+
definitions = Flexibility.view_definitions_for(@document)
|
|
27
|
+
fields = definitions.filter_map do |name, options|
|
|
28
|
+
options = options.to_h.symbolize_keys
|
|
29
|
+
term = (options[:render_term] || name).to_sym
|
|
30
|
+
next unless public?(name, options) && (term == :collection || presenter.respond_to?(term))
|
|
31
|
+
|
|
32
|
+
Field.new(name: term, label: label(term, options), options: options)
|
|
33
|
+
end
|
|
34
|
+
fields << collection_field unless collection_defined?(definitions)
|
|
35
|
+
IiifPrint.sort_af_fields!(fields, sort_order: @sort_order)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def collection_field
|
|
41
|
+
Field.new(name: :collection, label: Hyrax::Renderers::AttributeRenderer.new(:collection, nil).label)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def collection_defined?(definitions)
|
|
45
|
+
definitions.any? { |name, options| [name.to_s, options.to_h.symbolize_keys[:render_term].to_s].include?('collection') }
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# The show page lists an admin note for editors only, whatever the profile says.
|
|
49
|
+
def public?(name, options)
|
|
50
|
+
return false if name.to_s == 'admin_note'
|
|
51
|
+
|
|
52
|
+
!(options[:admin_only] || options[:editor_only] || options[:show_page] == false)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def label(name, options)
|
|
56
|
+
labels = options[:display_label] || {}
|
|
57
|
+
label = (labels[I18n.locale.to_s] || labels['default'] || name).to_s
|
|
58
|
+
translated = I18n.t(label, default: label) if label.include?('.')
|
|
59
|
+
return translated if translated && translated != label
|
|
60
|
+
|
|
61
|
+
I18n.t(:"blacklight.search.fields.index.#{label}",
|
|
62
|
+
default: [:"blacklight.search.fields.show.#{label}", :"blacklight.search.fields.#{label}", label.humanize])
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module IiifPrint
|
|
4
|
+
module Flexibility
|
|
5
|
+
##
|
|
6
|
+
# A flexible field's values, read from the show presenter and rendered the way its profile's `render_as` renders
|
|
7
|
+
# them on the show page.
|
|
8
|
+
class Values
|
|
9
|
+
# What IIIF Presentation 3.0 allows in a metadata value (section 4.5).
|
|
10
|
+
IIIF_TAGS = %w[a b br i img p small span sub sup].freeze
|
|
11
|
+
IIIF_ATTRIBUTES = %w[href src alt].freeze
|
|
12
|
+
RIGHTS_SERVICES = %w[rights_statement license].freeze
|
|
13
|
+
|
|
14
|
+
# @param work [SolrDocument, SolrHit]
|
|
15
|
+
# @param presenter [#display_values_for] the record's show presenter
|
|
16
|
+
# @param base_url [String]
|
|
17
|
+
# @param autolink [#call] turns URLs in plain text into links
|
|
18
|
+
def initialize(work:, presenter:, base_url:, autolink:)
|
|
19
|
+
@work = work
|
|
20
|
+
@presenter = presenter
|
|
21
|
+
@base_url = base_url
|
|
22
|
+
@autolink = autolink
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# @return [Array] the field's values as stored, blanks dropped
|
|
26
|
+
def raw(field_name)
|
|
27
|
+
Array(@presenter.try(field_name)).reject(&:blank?)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# @return [Array<String>] the field's values as html
|
|
31
|
+
def rendered(field_name, options)
|
|
32
|
+
options ||= {}
|
|
33
|
+
values = Array(@presenter.try(field_name)).reject(&:blank?)
|
|
34
|
+
return [values.map { |entry| "<p>#{compound_value(field_name, entry)}</p>" }.join] if options[:render_as].to_s == 'compound'
|
|
35
|
+
|
|
36
|
+
labels = labels_for(field_name, values)
|
|
37
|
+
values.map { |value| value(field_name, value.to_s, labels[value.to_s], options) }
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
# Keyed by value, as the show page's renderers get them in `options[:labels]`, and like them treating a blank
|
|
43
|
+
# label, or one equal to its value, as none.
|
|
44
|
+
def labels_for(field_name, values)
|
|
45
|
+
labels = @presenter.try(:controlled_labels_for, field_name, values) || display_labels(field_name, values)
|
|
46
|
+
labels.to_h.transform_keys(&:to_s).reject { |value, label| label.blank? || label.to_s == value }
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# TODO: drop once Hyrax's PresentsAttributes#controlled_labels_for is public
|
|
50
|
+
def display_labels(field_name, values)
|
|
51
|
+
display = Array(@presenter.try(:display_values_for, field_name)).reject(&:blank?)
|
|
52
|
+
return {} unless display.size == values.size
|
|
53
|
+
|
|
54
|
+
values.map(&:to_s).zip(display.map(&:to_s)).to_h
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def value(field_name, value, label, options)
|
|
58
|
+
return search_value(options[:search_field] || field_name, value, label, options[:render_as].to_s) if %w[faceted linked].include?(options[:render_as].to_s)
|
|
59
|
+
|
|
60
|
+
label = rights_label(field_name, options[:render_as].to_s, value, label)
|
|
61
|
+
case options[:render_as].to_s
|
|
62
|
+
when 'redirects_label' then link(File.join(@base_url, value), File.join(@base_url, value))
|
|
63
|
+
when 'html' then sanitize_html(value)
|
|
64
|
+
when 'date' then ERB::Util.h(formatted_date(value))
|
|
65
|
+
else labeled_value(value, label)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Like Hyrax's faceted and linked renderers: a controlled term links by its label, through the label facet
|
|
70
|
+
# when the catalog registers one.
|
|
71
|
+
def search_value(field, value, label, render_as)
|
|
72
|
+
return search_link({ search_field: field, q: label || value }, label || value) if render_as == 'linked'
|
|
73
|
+
|
|
74
|
+
by_label = label.present? && label_facet?(field)
|
|
75
|
+
search_link({ "f[#{field}#{'_label' if by_label}_sim][]": by_label ? label : value }, label || value)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def label_facet?(field)
|
|
79
|
+
config = 'CatalogController'.safe_constantize.try(:blacklight_config)
|
|
80
|
+
config.respond_to?(:facet_fields) && config.facet_fields.key?("#{field}_label_sim")
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def search_link(params, text)
|
|
84
|
+
params = params.merge(include_child_works: true) if @work["is_child_bsi"] == true
|
|
85
|
+
link(File.join(@base_url, Rails.application.routes.url_helpers.search_catalog_path(**params, locale: I18n.locale)), text)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def labeled_value(value, label)
|
|
89
|
+
return @autolink.call([ERB::Util.h(value)]).first if label.blank?
|
|
90
|
+
return ERB::Util.h(label) unless value.match?(%r{\Ahttps?://\S+\z})
|
|
91
|
+
|
|
92
|
+
link(value, label)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def formatted_date(value)
|
|
96
|
+
Date.parse(value).to_formatted_s(:standard)
|
|
97
|
+
rescue ArgumentError
|
|
98
|
+
value
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# A rights statement or license rendered as such takes its label from its Hyrax service, as the show page's
|
|
102
|
+
# renderers do; one rendered otherwise falls back to the service only when no label was indexed.
|
|
103
|
+
def rights_label(field_name, render_as, value, label)
|
|
104
|
+
return service_label(render_as, value) || label if RIGHTS_SERVICES.include?(render_as)
|
|
105
|
+
return label || service_label(field_name.to_s, value) if RIGHTS_SERVICES.include?(field_name.to_s)
|
|
106
|
+
|
|
107
|
+
label
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def service_label(service, value)
|
|
111
|
+
Hyrax.config.try("#{service}_service_class")&.new&.label(value) { nil }
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def sanitize_html(value)
|
|
115
|
+
fragment = Nokogiri::HTML.fragment(value.to_s)
|
|
116
|
+
{ 'a' => 'href', 'img' => 'src' }.each do |tag, attribute|
|
|
117
|
+
fragment.css("#{tag}[#{attribute}]").each { |node| node[attribute] = absolute_url(node[attribute]) }
|
|
118
|
+
end
|
|
119
|
+
Rails::Html::SafeListSanitizer.new.sanitize(fragment.to_html, tags: IIIF_TAGS, attributes: IIIF_ATTRIBUTES).strip
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def absolute_url(url)
|
|
123
|
+
return url if url.blank? || url.match?(/\A[a-z][a-z0-9+.-]*:/i)
|
|
124
|
+
|
|
125
|
+
URI.join("#{@base_url.to_s.chomp('/')}/", url).to_s
|
|
126
|
+
rescue URI::Error
|
|
127
|
+
url
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# One entry as Hyrax's compound renderer, and any decorator the app gives it, renders it on the show page, with
|
|
131
|
+
# a line break where each innermost block ended, since IIIF allows no blocks.
|
|
132
|
+
def compound_value(field_name, entry)
|
|
133
|
+
renderer = Hyrax::Renderers::CompoundAttributeRenderer.new(field_name, [entry], subproperties: compound_subproperties(field_name))
|
|
134
|
+
fragment = Nokogiri::HTML.fragment(renderer.render_value)
|
|
135
|
+
fragment.css('div').each { |div| div.add_next_sibling('<br>') unless div.at_css('div') }
|
|
136
|
+
sanitize_html(fragment.to_html).gsub(/\s*<br>\s*/, '<br>').sub(/(<br>)+\z/, '')
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def compound_subproperties(field_name)
|
|
140
|
+
@presenter.send(:compound_subproperties_for, field_name) if @presenter.respond_to?(:compound_subproperties_for, true)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def link(href, text)
|
|
144
|
+
%(<a href="#{ERB::Util.h(href)}">#{ERB::Util.h(text)}</a>)
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "iiif_print/flexibility/fields"
|
|
4
|
+
require "iiif_print/flexibility/values"
|
|
5
|
+
|
|
6
|
+
module IiifPrint
|
|
7
|
+
##
|
|
8
|
+
# IIIF manifest metadata for records indexed under an M3 profile, built the way their show page is: which fields
|
|
9
|
+
# from {IiifPrint::Flexibility::Fields}, and how each value renders from {IiifPrint::Flexibility::Values}.
|
|
10
|
+
module Flexibility
|
|
11
|
+
class << self
|
|
12
|
+
##
|
|
13
|
+
# @return [Boolean] whether the record's metadata comes from its M3 profile
|
|
14
|
+
def applies_to?(document)
|
|
15
|
+
Hyrax.config.try(:flexible?) && document.try(:flexible?)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def presenter_for(document, ability)
|
|
19
|
+
return Hyrax::FileSetPresenter.new(document, ability) if document.file_set?
|
|
20
|
+
|
|
21
|
+
controller = "Hyrax::#{document.hydra_model.model_name.collection.camelize}Controller".safe_constantize
|
|
22
|
+
(controller&.show_presenter || Hyrax::WorkShowPresenter).new(document, ability)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
##
|
|
26
|
+
# The profile's view definitions for the record, plus its title, description and abstract when the profile
|
|
27
|
+
# gives them no view block, since the show page shows those outside its field list. Read once per request
|
|
28
|
+
# for each tenant, schema, version and context; each tenant numbers its own profile versions.
|
|
29
|
+
def view_definitions_for(document)
|
|
30
|
+
cache = RequestStore.store[:iiif_print_view_definitions] ||= {}
|
|
31
|
+
version = document.try(:schema_version)
|
|
32
|
+
contexts = document.try(:contexts)
|
|
33
|
+
tenant = Apartment::Tenant.current if defined?(Apartment::Tenant)
|
|
34
|
+
cache[[tenant, schema_name(document), version, contexts]] ||= begin
|
|
35
|
+
definitions = Hyrax::Schema.m3_schema_loader.view_definitions_for(schema: schema_name(document), version: version, contexts: contexts)
|
|
36
|
+
lead_definitions(document, definitions).merge(definitions.to_h.symbolize_keys)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
LEAD_FIELDS = %i[title description abstract].freeze
|
|
43
|
+
|
|
44
|
+
def lead_definitions(document, definitions)
|
|
45
|
+
attributes = profile_attributes(document)
|
|
46
|
+
(LEAD_FIELDS - definitions.to_h.keys.map(&:to_sym)).each_with_object({}) do |name, lead|
|
|
47
|
+
config = attributes[name.to_s]
|
|
48
|
+
lead[name] = Hyrax::SchemaLoader::AttributeDefinition.new(name.to_s, config).view_options if config
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def profile_attributes(document)
|
|
53
|
+
schema = Hyrax::FlexibleSchema.find_by(id: document.try(:schema_version)) || Hyrax::FlexibleSchema.order(:created_at).last
|
|
54
|
+
schema.try(:attributes_for, schema_name(document)) || {}
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def schema_name(document)
|
|
58
|
+
Valkyrie.config.resource_class_resolver.call(document.hydra_model_name).to_s
|
|
59
|
+
rescue NameError
|
|
60
|
+
document.hydra_model.to_s
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
data/lib/iiif_print/metadata.rb
CHANGED
|
@@ -38,13 +38,13 @@ module IiifPrint
|
|
|
38
38
|
if version == 2
|
|
39
39
|
case property
|
|
40
40
|
when :label then field.label
|
|
41
|
-
when :value then
|
|
41
|
+
when :value then rendered_values_for(field)
|
|
42
42
|
when :collection then make_collection_link(viewable_collections)
|
|
43
43
|
end
|
|
44
44
|
elsif version == 3
|
|
45
45
|
case property
|
|
46
46
|
when :label then { I18n.locale.to_s => [field.label] }
|
|
47
|
-
when :value then { 'none' =>
|
|
47
|
+
when :value then { 'none' => rendered_values_for(field) }
|
|
48
48
|
when :collection then { 'none' => make_collection_link(viewable_collections) }
|
|
49
49
|
end
|
|
50
50
|
end
|
|
@@ -64,6 +64,12 @@ module IiifPrint
|
|
|
64
64
|
Loofah.fragment(value).scrub!(:whitewash).to_s
|
|
65
65
|
end
|
|
66
66
|
|
|
67
|
+
def rendered_values_for(field)
|
|
68
|
+
return flexible_values.rendered(field.name, field.options) if flexible?
|
|
69
|
+
|
|
70
|
+
cast_to_value(field_name: field.name, options: field.options)
|
|
71
|
+
end
|
|
72
|
+
|
|
67
73
|
def cast_to_value(field_name:, options:)
|
|
68
74
|
if options&.[](:render_as) == :faceted
|
|
69
75
|
faceted_values_for(field_name: field_name)
|
|
@@ -98,14 +104,25 @@ module IiifPrint
|
|
|
98
104
|
end
|
|
99
105
|
|
|
100
106
|
def values_for(field_name:)
|
|
107
|
+
return flexible_values.raw(field_name.try(:name) || field_name) if flexible?
|
|
108
|
+
|
|
101
109
|
field_name = field_name.try(:name) || field_name
|
|
102
110
|
# TODO: we are assuming tesim or dtsi (for dates), might want to account for other suffixes in the future
|
|
103
111
|
Array(work["#{field_name}_tesim"] || work["#{field_name}_dtsi"]&.to_date.try(:to_formatted_s, :standard))
|
|
104
112
|
end
|
|
105
113
|
|
|
114
|
+
def flexible?
|
|
115
|
+
Flexibility.applies_to?(work)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def flexible_values
|
|
119
|
+
@flexible_values ||= Flexibility::Values.new(work: work, presenter: Flexibility.presenter_for(work, current_ability),
|
|
120
|
+
base_url: @base_url, autolink: method(:make_link))
|
|
121
|
+
end
|
|
122
|
+
|
|
106
123
|
def make_collection_link(collection_documents)
|
|
107
124
|
collection_documents.map do |collection|
|
|
108
|
-
"<a href='#{File.join(@base_url, 'collections', collection.id)}'>#{collection.title.first}</a>"
|
|
125
|
+
"<a href='#{File.join(@base_url, 'collections', collection.id)}'>#{ERB::Util.h(collection.title.first)}</a>"
|
|
109
126
|
end
|
|
110
127
|
end
|
|
111
128
|
|
data/lib/iiif_print/version.rb
CHANGED
data/lib/iiif_print.rb
CHANGED
|
@@ -13,6 +13,7 @@ require "iiif_print/text_formats_from_alto_service"
|
|
|
13
13
|
require "iiif_print/tiff_derivative_service"
|
|
14
14
|
require "iiif_print/lineage_service"
|
|
15
15
|
require "iiif_print/metadata"
|
|
16
|
+
require "iiif_print/flexibility"
|
|
16
17
|
require "iiif_print/split_pdfs/base_splitter"
|
|
17
18
|
require "iiif_print/split_pdfs/child_work_creation_from_pdf_service"
|
|
18
19
|
require "iiif_print/split_pdfs/derivative_rodeo_splitter"
|
|
@@ -203,8 +204,27 @@ module IiifPrint
|
|
|
203
204
|
def self.manifest_metadata_from(work:, presenter:)
|
|
204
205
|
current_ability = presenter.try(:ability) || presenter.try(:current_ability)
|
|
205
206
|
base_url = presenter.try(:base_url) || presenter.try(:request)&.base_url
|
|
207
|
+
document = work.is_a?(::SolrDocument) ? work : ::SolrDocument.new(work)
|
|
208
|
+
return flexible_manifest_metadata_for(document, base_url: base_url) if Flexibility.applies_to?(document)
|
|
209
|
+
|
|
206
210
|
IiifPrint.manifest_metadata_for(work: work, current_ability: current_ability, base_url: base_url)
|
|
207
211
|
end
|
|
212
|
+
|
|
213
|
+
# @api private
|
|
214
|
+
#
|
|
215
|
+
# A flexible work's metadata lists the fields an anonymous visitor would see on its show page, whoever asked
|
|
216
|
+
# and whether or not the work itself is public.
|
|
217
|
+
def self.flexible_manifest_metadata_for(document, base_url:)
|
|
218
|
+
ability = anonymous_ability
|
|
219
|
+
manifest_metadata_for(work: document, fields: Flexibility::Fields.new(document, ability).to_a, current_ability: ability, base_url: base_url)
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
# One per request: an Ability is costly to build, and a manifest can ask once for every page.
|
|
223
|
+
def self.anonymous_ability
|
|
224
|
+
RequestStore.store[:iiif_print_anonymous_ability] ||= ::Ability.new(nil)
|
|
225
|
+
end
|
|
226
|
+
private_class_method :flexible_manifest_metadata_for, :anonymous_ability
|
|
227
|
+
|
|
208
228
|
# Hash is an arbitrary attribute key/value pairs
|
|
209
229
|
# Struct is a defined set of attribute "keys". When we favor defined values,
|
|
210
230
|
# then we are naming the concept and defining the range of potential values.
|
|
@@ -273,10 +293,10 @@ module IiifPrint
|
|
|
273
293
|
def self.sort_af_fields!(fields, sort_order:)
|
|
274
294
|
return fields if sort_order.blank?
|
|
275
295
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
end
|
|
296
|
+
remaining = sort_order.index(:remaining) || sort_order.length
|
|
297
|
+
fields.each_with_index.sort_by do |field, index|
|
|
298
|
+
[sort_order.index(field.name.to_sym) || remaining, index]
|
|
299
|
+
end.map(&:first)
|
|
280
300
|
end
|
|
281
301
|
|
|
282
302
|
##
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: iiif_print
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sean Upton
|
|
@@ -97,6 +97,20 @@ dependencies:
|
|
|
97
97
|
- - "~>"
|
|
98
98
|
- !ruby/object:Gem::Version
|
|
99
99
|
version: '3.0'
|
|
100
|
+
- !ruby/object:Gem::Dependency
|
|
101
|
+
name: request_store
|
|
102
|
+
requirement: !ruby/object:Gem::Requirement
|
|
103
|
+
requirements:
|
|
104
|
+
- - ">="
|
|
105
|
+
- !ruby/object:Gem::Version
|
|
106
|
+
version: '1.0'
|
|
107
|
+
type: :runtime
|
|
108
|
+
prerelease: false
|
|
109
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
110
|
+
requirements:
|
|
111
|
+
- - ">="
|
|
112
|
+
- !ruby/object:Gem::Version
|
|
113
|
+
version: '1.0'
|
|
100
114
|
- !ruby/object:Gem::Dependency
|
|
101
115
|
name: bixby
|
|
102
116
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -456,6 +470,9 @@ files:
|
|
|
456
470
|
- lib/iiif_print/data/work_files.rb
|
|
457
471
|
- lib/iiif_print/engine.rb
|
|
458
472
|
- lib/iiif_print/errors.rb
|
|
473
|
+
- lib/iiif_print/flexibility.rb
|
|
474
|
+
- lib/iiif_print/flexibility/fields.rb
|
|
475
|
+
- lib/iiif_print/flexibility/values.rb
|
|
459
476
|
- lib/iiif_print/homepage_search_builder.rb
|
|
460
477
|
- lib/iiif_print/image_tool.rb
|
|
461
478
|
- lib/iiif_print/jp2_derivative_service.rb
|