iiif-presentation 1.4.2 → 1.5.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/.github/workflows/ruby.yml +8 -1
- data/.standard.yml +1 -0
- data/Gemfile +5 -5
- data/README.md +1 -1
- data/Rakefile +4 -2
- data/VERSION +1 -1
- data/bin/standardrb +16 -0
- data/iiif-presentation.gemspec +23 -23
- data/lib/iiif/hash_behaviours.rb +29 -33
- data/lib/iiif/ordered_hash.rb +33 -33
- data/lib/iiif/presentation/abstract_resource.rb +17 -22
- data/lib/iiif/presentation/annotation.rb +9 -11
- data/lib/iiif/presentation/annotation_list.rb +8 -10
- data/lib/iiif/presentation/canvas.rb +11 -13
- data/lib/iiif/presentation/collection.rb +7 -9
- data/lib/iiif/presentation/image_resource.rb +33 -35
- data/lib/iiif/presentation/layer.rb +8 -10
- data/lib/iiif/presentation/manifest.rb +9 -12
- data/lib/iiif/presentation/range.rb +8 -10
- data/lib/iiif/presentation/resource.rb +5 -7
- data/lib/iiif/presentation/sequence.rb +8 -11
- data/lib/iiif/presentation/service.rb +1 -2
- data/lib/iiif/presentation.rb +7 -7
- data/lib/iiif/service.rb +121 -102
- data/lib/iiif/v3/abstract_resource.rb +127 -130
- data/lib/iiif/v3/presentation/annotation.rb +20 -21
- data/lib/iiif/v3/presentation/annotation_collection.rb +7 -9
- data/lib/iiif/v3/presentation/annotation_page.rb +14 -15
- data/lib/iiif/v3/presentation/canvas.rb +21 -22
- data/lib/iiif/v3/presentation/choice.rb +14 -15
- data/lib/iiif/v3/presentation/collection.rb +7 -8
- data/lib/iiif/v3/presentation/image_resource.rb +21 -22
- data/lib/iiif/v3/presentation/manifest.rb +18 -19
- data/lib/iiif/v3/presentation/nav_place.rb +125 -29
- data/lib/iiif/v3/presentation/range.rb +10 -10
- data/lib/iiif/v3/presentation/resource.rb +4 -5
- data/lib/iiif/v3/presentation/sequence.rb +10 -11
- data/lib/iiif/v3/presentation/service.rb +12 -13
- data/lib/iiif/v3/presentation.rb +8 -8
- data/spec/integration/iiif/presentation/image_resource_spec.rb +54 -58
- data/spec/integration/iiif/service_spec.rb +76 -77
- data/spec/integration/iiif/v3/abstract_resource_spec.rb +72 -73
- data/spec/integration/iiif/v3/presentation/image_resource_spec.rb +53 -56
- data/spec/spec_helper.rb +56 -64
- data/spec/unit/iiif/hash_behaviours_spec.rb +384 -387
- data/spec/unit/iiif/ordered_hash_spec.rb +86 -91
- data/spec/unit/iiif/presentation/abstract_resource_spec.rb +64 -70
- data/spec/unit/iiif/presentation/annotation_list_spec.rb +1 -3
- data/spec/unit/iiif/presentation/annotation_spec.rb +1 -3
- data/spec/unit/iiif/presentation/canvas_spec.rb +11 -14
- data/spec/unit/iiif/presentation/collection_spec.rb +26 -33
- data/spec/unit/iiif/presentation/image_resource_spec.rb +4 -6
- data/spec/unit/iiif/presentation/layer_spec.rb +16 -20
- data/spec/unit/iiif/presentation/manifest_spec.rb +45 -48
- data/spec/unit/iiif/presentation/range_spec.rb +18 -22
- data/spec/unit/iiif/presentation/resource_spec.rb +3 -6
- data/spec/unit/iiif/presentation/sequence_spec.rb +58 -63
- data/spec/unit/iiif/presentation/shared_examples/abstract_resource_only_keys.rb +4 -10
- data/spec/unit/iiif/presentation/shared_examples/any_type_keys.rb +5 -9
- data/spec/unit/iiif/presentation/shared_examples/array_only_keys.rb +9 -17
- data/spec/unit/iiif/presentation/shared_examples/int_only_keys.rb +6 -14
- data/spec/unit/iiif/presentation/shared_examples/string_only_keys.rb +6 -13
- data/spec/unit/iiif/service_spec.rb +8 -13
- data/spec/unit/iiif/v3/abstract_resource_define_methods_for_spec.rb +39 -37
- data/spec/unit/iiif/v3/abstract_resource_spec.rb +124 -131
- data/spec/unit/iiif/v3/presentation/annotation_collection_spec.rb +14 -17
- data/spec/unit/iiif/v3/presentation/annotation_page_spec.rb +71 -69
- data/spec/unit/iiif/v3/presentation/annotation_spec.rb +249 -233
- data/spec/unit/iiif/v3/presentation/canvas_spec.rb +211 -193
- data/spec/unit/iiif/v3/presentation/choice_spec.rb +81 -77
- data/spec/unit/iiif/v3/presentation/collection_spec.rb +24 -29
- data/spec/unit/iiif/v3/presentation/image_resource_spec.rb +70 -71
- data/spec/unit/iiif/v3/presentation/manifest_spec.rb +248 -235
- data/spec/unit/iiif/v3/presentation/nav_place_spec.rb +249 -49
- data/spec/unit/iiif/v3/presentation/range_spec.rb +28 -29
- data/spec/unit/iiif/v3/presentation/resource_spec.rb +83 -82
- data/spec/unit/iiif/v3/presentation/sequence_spec.rb +125 -119
- data/spec/unit/iiif/v3/presentation/service_spec.rb +123 -124
- data/spec/unit/iiif/v3/presentation/shared_examples/abstract_resource_only_keys.rb +4 -8
- data/spec/unit/iiif/v3/presentation/shared_examples/any_type_keys.rb +5 -7
- data/spec/unit/iiif/v3/presentation/shared_examples/array_only_keys.rb +9 -13
- data/spec/unit/iiif/v3/presentation/shared_examples/hash_only_keys.rb +9 -13
- data/spec/unit/iiif/v3/presentation/shared_examples/int_only_keys.rb +6 -10
- data/spec/unit/iiif/v3/presentation/shared_examples/numeric_only_keys.rb +6 -10
- data/spec/unit/iiif/v3/presentation/shared_examples/string_only_keys.rb +6 -10
- data/spec/unit/iiif/v3/presentation/shared_examples/uri_only_keys.rb +9 -13
- metadata +26 -65
|
@@ -2,19 +2,18 @@ module IIIF
|
|
|
2
2
|
module V3
|
|
3
3
|
module Presentation
|
|
4
4
|
class AnnotationCollection < IIIF::V3::AbstractResource
|
|
5
|
-
|
|
6
|
-
TYPE = 'AnnotationCollection'.freeze
|
|
5
|
+
TYPE = "AnnotationCollection".freeze
|
|
7
6
|
|
|
8
7
|
def required_keys
|
|
9
|
-
super + %w
|
|
8
|
+
super + %w[id]
|
|
10
9
|
end
|
|
11
10
|
|
|
12
11
|
def int_only_keys
|
|
13
|
-
super + %w
|
|
12
|
+
super + %w[total]
|
|
14
13
|
end
|
|
15
14
|
|
|
16
15
|
def array_only_keys
|
|
17
|
-
super + %w
|
|
16
|
+
super + %w[content]
|
|
18
17
|
end
|
|
19
18
|
|
|
20
19
|
# TODO: paging properties
|
|
@@ -27,11 +26,10 @@ module IIIF
|
|
|
27
26
|
#
|
|
28
27
|
# don't forget to validate
|
|
29
28
|
|
|
30
|
-
def initialize(hsh={})
|
|
31
|
-
hsh[
|
|
32
|
-
super
|
|
29
|
+
def initialize(hsh = {})
|
|
30
|
+
hsh["type"] = TYPE unless hsh.has_key? "type"
|
|
31
|
+
super
|
|
33
32
|
end
|
|
34
|
-
|
|
35
33
|
end
|
|
36
34
|
end
|
|
37
35
|
end
|
|
@@ -2,47 +2,46 @@ module IIIF
|
|
|
2
2
|
module V3
|
|
3
3
|
module Presentation
|
|
4
4
|
class AnnotationPage < IIIF::V3::AbstractResource
|
|
5
|
-
|
|
6
|
-
TYPE = 'AnnotationPage'.freeze
|
|
5
|
+
TYPE = "AnnotationPage".freeze
|
|
7
6
|
|
|
8
7
|
def required_keys
|
|
9
|
-
super + %w
|
|
8
|
+
super + %w[id]
|
|
10
9
|
end
|
|
11
10
|
|
|
12
11
|
def prohibited_keys
|
|
13
12
|
super + CONTENT_RESOURCE_PROPERTIES +
|
|
14
|
-
%w
|
|
13
|
+
%w[first last total nav_date viewing_direction start_canvas content_annotations]
|
|
15
14
|
end
|
|
16
15
|
|
|
17
16
|
def uri_only_keys
|
|
18
|
-
super + %w
|
|
17
|
+
super + %w[id]
|
|
19
18
|
end
|
|
20
19
|
|
|
21
|
-
def array_only_keys
|
|
22
|
-
super + %w
|
|
20
|
+
def array_only_keys
|
|
21
|
+
super + %w[items]
|
|
23
22
|
end
|
|
24
23
|
|
|
25
24
|
def legal_viewing_hint_values
|
|
26
|
-
super + %w
|
|
25
|
+
super + %w[none]
|
|
27
26
|
end
|
|
28
27
|
|
|
29
|
-
def initialize(hsh={})
|
|
30
|
-
hsh[
|
|
31
|
-
super
|
|
28
|
+
def initialize(hsh = {})
|
|
29
|
+
hsh["type"] = TYPE unless hsh.has_key? "type"
|
|
30
|
+
super
|
|
32
31
|
end
|
|
33
32
|
|
|
34
33
|
def validate
|
|
35
34
|
super
|
|
36
35
|
|
|
37
|
-
unless self[
|
|
36
|
+
unless /^https?:/.match?(self["id"])
|
|
38
37
|
err_msg = "id must be an http(s) URI for #{self.class}"
|
|
39
38
|
raise IIIF::V3::Presentation::IllegalValueError, err_msg
|
|
40
39
|
end
|
|
41
40
|
|
|
42
|
-
items = self[
|
|
43
|
-
if items
|
|
41
|
+
items = self["items"]
|
|
42
|
+
if items&.any?
|
|
44
43
|
unless items.all? { |entry| entry.instance_of?(IIIF::V3::Presentation::Annotation) }
|
|
45
|
-
err_msg =
|
|
44
|
+
err_msg = "All entries in the items list must be a IIIF::V3::Presentation::Annotation"
|
|
46
45
|
raise IIIF::V3::Presentation::IllegalValueError, err_msg
|
|
47
46
|
end
|
|
48
47
|
end
|
|
@@ -2,54 +2,53 @@ module IIIF
|
|
|
2
2
|
module V3
|
|
3
3
|
module Presentation
|
|
4
4
|
class Canvas < IIIF::V3::AbstractResource
|
|
5
|
-
|
|
6
|
-
TYPE = 'Canvas'.freeze
|
|
5
|
+
TYPE = "Canvas".freeze
|
|
7
6
|
|
|
8
7
|
def required_keys
|
|
9
|
-
super + %w
|
|
8
|
+
super + %w[id label]
|
|
10
9
|
end
|
|
11
10
|
|
|
12
11
|
def prohibited_keys
|
|
13
|
-
super + PAGING_PROPERTIES + %w
|
|
12
|
+
super + PAGING_PROPERTIES + %w[viewing_direction format nav_date start_canvas content_annotations]
|
|
14
13
|
end
|
|
15
14
|
|
|
16
15
|
def int_only_keys
|
|
17
|
-
super + %w
|
|
16
|
+
super + %w[depth]
|
|
18
17
|
end
|
|
19
18
|
|
|
20
19
|
def array_only_keys
|
|
21
|
-
super + %w
|
|
20
|
+
super + %w[content]
|
|
22
21
|
end
|
|
23
22
|
|
|
24
23
|
def legal_viewing_hint_values
|
|
25
|
-
super + %w
|
|
24
|
+
super + %w[paged continuous non-paged facing-pages auto-advance]
|
|
26
25
|
end
|
|
27
26
|
|
|
28
|
-
def initialize(hsh={})
|
|
29
|
-
hsh[
|
|
30
|
-
super
|
|
27
|
+
def initialize(hsh = {})
|
|
28
|
+
hsh["type"] = TYPE unless hsh.has_key? "type"
|
|
29
|
+
super
|
|
31
30
|
end
|
|
32
31
|
|
|
33
32
|
def validate
|
|
34
33
|
super
|
|
35
34
|
|
|
36
|
-
id_uri = URI.parse(self[
|
|
37
|
-
unless self[
|
|
35
|
+
id_uri = URI.parse(self["id"])
|
|
36
|
+
unless self["id"] =~ /^https?:/ && id_uri.fragment.nil?
|
|
38
37
|
err_msg = "id must be an http(s) URI without a fragment for #{self.class}"
|
|
39
38
|
raise IIIF::V3::Presentation::IllegalValueError, err_msg
|
|
40
39
|
end
|
|
41
40
|
|
|
42
|
-
content = self[
|
|
43
|
-
if content
|
|
41
|
+
content = self["content"]
|
|
42
|
+
if content&.any?
|
|
44
43
|
unless content.all? { |entry| entry.instance_of?(IIIF::V3::Presentation::AnnotationPage) }
|
|
45
|
-
err_msg =
|
|
44
|
+
err_msg = "All entries in the content list must be a IIIF::V3::Presentation::AnnotationPage"
|
|
46
45
|
raise IIIF::V3::Presentation::IllegalValueError, err_msg
|
|
47
46
|
end
|
|
48
47
|
content.each do |anno_page|
|
|
49
|
-
annos = anno_page[
|
|
50
|
-
if annos
|
|
51
|
-
unless annos.all? { |anno| anno.target ==
|
|
52
|
-
err_msg =
|
|
48
|
+
annos = anno_page["items"]
|
|
49
|
+
if annos&.any?
|
|
50
|
+
unless annos.all? { |anno| anno.target == id }
|
|
51
|
+
err_msg = "URI of the canvas must be repeated in the target field of included Annotations"
|
|
53
52
|
raise IIIF::V3::Presentation::IllegalValueError, err_msg
|
|
54
53
|
end
|
|
55
54
|
end
|
|
@@ -58,9 +57,9 @@ module IIIF
|
|
|
58
57
|
|
|
59
58
|
# "A canvas MUST have exactly one width and one height, or exactly one duration.
|
|
60
59
|
# It may have width, height and duration.""
|
|
61
|
-
height = self[
|
|
62
|
-
width = self[
|
|
63
|
-
if
|
|
60
|
+
height = self["height"]
|
|
61
|
+
width = self["width"]
|
|
62
|
+
if !!height ^ !!width # this is an exclusive or: forces height and width to boolean
|
|
64
63
|
extent_err_msg = "#{self.class} requires both height and width or neither"
|
|
65
64
|
raise IIIF::V3::Presentation::IllegalValueError, extent_err_msg
|
|
66
65
|
end
|
|
@@ -2,45 +2,44 @@ module IIIF
|
|
|
2
2
|
module V3
|
|
3
3
|
module Presentation
|
|
4
4
|
class Choice < IIIF::V3::AbstractResource
|
|
5
|
-
|
|
6
|
-
TYPE = 'Choice'.freeze
|
|
5
|
+
TYPE = "Choice".freeze
|
|
7
6
|
|
|
8
7
|
def prohibited_keys
|
|
9
8
|
super + CONTENT_RESOURCE_PROPERTIES + PAGING_PROPERTIES +
|
|
10
|
-
|
|
9
|
+
%w[nav_date viewing_direction start_canvas content_annotations]
|
|
11
10
|
end
|
|
12
11
|
|
|
13
12
|
def any_type_keys
|
|
14
|
-
super + %w
|
|
13
|
+
super + %w[default]
|
|
15
14
|
end
|
|
16
15
|
|
|
17
16
|
def string_only_keys
|
|
18
|
-
super + %w
|
|
17
|
+
super + %w[choice_hint]
|
|
19
18
|
end
|
|
20
19
|
|
|
21
|
-
def array_only_keys
|
|
22
|
-
super + %w
|
|
20
|
+
def array_only_keys
|
|
21
|
+
super + %w[items]
|
|
23
22
|
end
|
|
24
23
|
|
|
25
24
|
def legal_viewing_hint_values
|
|
26
|
-
%w
|
|
25
|
+
%w[none]
|
|
27
26
|
end
|
|
28
27
|
|
|
29
28
|
def legal_choice_hint_values
|
|
30
|
-
%w
|
|
29
|
+
%w[client user]
|
|
31
30
|
end
|
|
32
31
|
|
|
33
|
-
def initialize(hsh={})
|
|
34
|
-
hsh[
|
|
35
|
-
super
|
|
32
|
+
def initialize(hsh = {})
|
|
33
|
+
hsh["type"] = TYPE unless hsh.has_key? "type"
|
|
34
|
+
super
|
|
36
35
|
end
|
|
37
36
|
|
|
38
37
|
def validate
|
|
39
38
|
super
|
|
40
39
|
|
|
41
|
-
if
|
|
42
|
-
unless
|
|
43
|
-
m = "choiceHint for #{self.class} must be one of #{
|
|
40
|
+
if has_key?("choice_hint")
|
|
41
|
+
unless legal_choice_hint_values.include?(self["choice_hint"])
|
|
42
|
+
m = "choiceHint for #{self.class} must be one of #{legal_choice_hint_values}."
|
|
44
43
|
raise IIIF::V3::Presentation::IllegalValueError, m
|
|
45
44
|
end
|
|
46
45
|
end
|
|
@@ -2,15 +2,14 @@ module IIIF
|
|
|
2
2
|
module V3
|
|
3
3
|
module Presentation
|
|
4
4
|
class Collection < IIIF::V3::AbstractResource
|
|
5
|
-
|
|
6
|
-
TYPE = 'Collection'.freeze
|
|
5
|
+
TYPE = "Collection".freeze
|
|
7
6
|
|
|
8
7
|
def required_keys
|
|
9
|
-
super + %w
|
|
8
|
+
super + %w[id label]
|
|
10
9
|
end
|
|
11
10
|
|
|
12
11
|
def array_only_keys
|
|
13
|
-
super + %w
|
|
12
|
+
super + %w[collections manifests]
|
|
14
13
|
end
|
|
15
14
|
|
|
16
15
|
# TODO: navDate (collection or manifest only) - The value must be an xsd:dateTime literal in UTC, expressed in the form “YYYY-MM-DDThh:mm:ssZ”; There must be at most one navDate associated with any given resource.
|
|
@@ -24,12 +23,12 @@ module IIIF
|
|
|
24
23
|
# The value must be a non-negative integer.
|
|
25
24
|
|
|
26
25
|
def legal_viewing_hint_values
|
|
27
|
-
%w
|
|
26
|
+
%w[auto-advance together]
|
|
28
27
|
end
|
|
29
28
|
|
|
30
|
-
def initialize(hsh={})
|
|
31
|
-
hsh[
|
|
32
|
-
super
|
|
29
|
+
def initialize(hsh = {})
|
|
30
|
+
hsh["type"] = TYPE unless hsh.has_key? "type"
|
|
31
|
+
super
|
|
33
32
|
end
|
|
34
33
|
|
|
35
34
|
def validate
|
|
@@ -1,20 +1,19 @@
|
|
|
1
|
-
require
|
|
1
|
+
require "faraday"
|
|
2
2
|
|
|
3
3
|
module IIIF
|
|
4
4
|
module V3
|
|
5
5
|
module Presentation
|
|
6
6
|
class ImageResource < Resource
|
|
7
|
+
TYPE = "Image".freeze
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
hsh['type'] = TYPE unless hsh.has_key? 'type'
|
|
12
|
-
super(hsh)
|
|
9
|
+
def initialize(hsh = {})
|
|
10
|
+
hsh["type"] = TYPE unless hsh.has_key? "type"
|
|
11
|
+
super
|
|
13
12
|
end
|
|
14
13
|
|
|
15
14
|
class << self
|
|
16
|
-
IMAGE_API_DEFAULT_PARAMS =
|
|
17
|
-
DEFAULT_FORMAT =
|
|
15
|
+
IMAGE_API_DEFAULT_PARAMS = "/full/!200,200/0/default.jpg".freeze
|
|
16
|
+
DEFAULT_FORMAT = "image/jpeg".freeze
|
|
18
17
|
# Create a new ImageResource that includes a IIIF Image API Service
|
|
19
18
|
# See http://iiif.io/api/presentation/2.0/#image-resources
|
|
20
19
|
#
|
|
@@ -54,8 +53,7 @@ module IIIF
|
|
|
54
53
|
# "width":1500
|
|
55
54
|
# }
|
|
56
55
|
#
|
|
57
|
-
def create_image_api_image_resource(params={})
|
|
58
|
-
|
|
56
|
+
def create_image_api_image_resource(params = {})
|
|
59
57
|
service_id = params.fetch(:service_id)
|
|
60
58
|
resource_id_default = "#{service_id}#{IMAGE_API_DEFAULT_PARAMS}"
|
|
61
59
|
resource_id = params.fetch(:resource_id, resource_id_default)
|
|
@@ -69,32 +67,33 @@ module IIIF
|
|
|
69
67
|
|
|
70
68
|
remote_info = get_info(service_id) if !have_whp || copy_info
|
|
71
69
|
|
|
72
|
-
resource =
|
|
73
|
-
resource[
|
|
70
|
+
resource = new
|
|
71
|
+
resource["id"] = resource_id
|
|
74
72
|
resource.format = format
|
|
75
|
-
resource.width = width.nil? ? remote_info[
|
|
76
|
-
resource.height = height.nil? ? remote_info[
|
|
73
|
+
resource.width = width.nil? ? remote_info["width"] : width
|
|
74
|
+
resource.height = height.nil? ? remote_info["height"] : height
|
|
77
75
|
resource_service = Service.new
|
|
78
76
|
if copy_info
|
|
79
77
|
resource_service.merge!(remote_info)
|
|
80
|
-
resource_service[
|
|
78
|
+
resource_service["id"] ||= resource_service.delete("@id")
|
|
81
79
|
else
|
|
82
|
-
resource_service[
|
|
83
|
-
if profile.nil?
|
|
84
|
-
if remote_info[
|
|
85
|
-
|
|
80
|
+
resource_service["id"] = service_id
|
|
81
|
+
resource_service["profile"] = if profile.nil?
|
|
82
|
+
if remote_info["profile"].is_a?(Array)
|
|
83
|
+
remote_info["profile"][0]
|
|
86
84
|
else
|
|
87
|
-
|
|
85
|
+
remote_info["profile"]
|
|
88
86
|
end
|
|
89
87
|
else
|
|
90
|
-
|
|
88
|
+
profile
|
|
91
89
|
end
|
|
92
90
|
end
|
|
93
91
|
resource.service = [resource_service]
|
|
94
|
-
|
|
92
|
+
resource
|
|
95
93
|
end
|
|
96
94
|
|
|
97
95
|
protected
|
|
96
|
+
|
|
98
97
|
def get_info(svc_id)
|
|
99
98
|
conn = Faraday.new("#{svc_id}/info.json") do |c|
|
|
100
99
|
c.use Faraday::Response::RaiseError
|
|
@@ -2,62 +2,61 @@ module IIIF
|
|
|
2
2
|
module V3
|
|
3
3
|
module Presentation
|
|
4
4
|
class Manifest < IIIF::V3::AbstractResource
|
|
5
|
-
|
|
6
|
-
TYPE = 'Manifest'.freeze
|
|
5
|
+
TYPE = "Manifest".freeze
|
|
7
6
|
|
|
8
7
|
def required_keys
|
|
9
8
|
# NOTE: relaxing requirement for items as Universal Viewer currently only accepts sequences
|
|
10
9
|
# see https://github.com/sul-dlss/osullivan/issues/27, sul-dlss/purl/issues/167
|
|
11
10
|
# super + %w{ id label items }
|
|
12
|
-
super + %w
|
|
11
|
+
super + %w[id label]
|
|
13
12
|
end
|
|
14
13
|
|
|
15
14
|
def prohibited_keys
|
|
16
|
-
super + CONTENT_RESOURCE_PROPERTIES + PAGING_PROPERTIES + %w
|
|
15
|
+
super + CONTENT_RESOURCE_PROPERTIES + PAGING_PROPERTIES + %w[start_canvas content_annotation]
|
|
17
16
|
end
|
|
18
17
|
|
|
19
18
|
def uri_only_keys
|
|
20
|
-
super + %w
|
|
19
|
+
super + %w[id]
|
|
21
20
|
end
|
|
22
21
|
|
|
23
22
|
def array_only_keys
|
|
24
23
|
# NOTE: allowing 'items' or 'sequences' as Universal Viewer currently only accepts sequences
|
|
25
24
|
# see https://github.com/sul-dlss/osullivan/issues/27, sul-dlss/purl/issues/167
|
|
26
25
|
# super + %w{ items structures }
|
|
27
|
-
super + %w
|
|
26
|
+
super + %w[items structures sequences]
|
|
28
27
|
end
|
|
29
28
|
|
|
30
29
|
def legal_viewing_hint_values
|
|
31
|
-
%w
|
|
30
|
+
%w[individuals paged continuous auto-advance]
|
|
32
31
|
end
|
|
33
32
|
|
|
34
|
-
def initialize(hsh={})
|
|
35
|
-
hsh[
|
|
36
|
-
super
|
|
33
|
+
def initialize(hsh = {})
|
|
34
|
+
hsh["type"] = TYPE unless hsh.has_key? "type"
|
|
35
|
+
super
|
|
37
36
|
end
|
|
38
37
|
|
|
39
38
|
def validate
|
|
40
39
|
super # also checks navDate format
|
|
41
40
|
|
|
42
|
-
unless self[
|
|
41
|
+
unless /^https?:/.match?(self["id"])
|
|
43
42
|
err_msg = "id must be an http(s) URI for #{self.class}"
|
|
44
43
|
raise IIIF::V3::Presentation::IllegalValueError, err_msg
|
|
45
44
|
end
|
|
46
45
|
|
|
47
46
|
# Items object list
|
|
48
|
-
unless self&.[](
|
|
49
|
-
m =
|
|
47
|
+
unless self&.[]("items")&.any?
|
|
48
|
+
m = "The items list must have at least one entry (and it must be a IIIF::V3::Presentation::Canvas)"
|
|
50
49
|
raise IIIF::V3::Presentation::MissingRequiredKeyError, m
|
|
51
50
|
end
|
|
52
|
-
validate_items_list(self[
|
|
51
|
+
validate_items_list(self["items"]) if self["items"]
|
|
53
52
|
|
|
54
53
|
# TODO: when embedding a sequence without any extensions within a manifest, the sequence must not have the @context field.
|
|
55
54
|
|
|
56
55
|
# TODO: AnnotationLists must not be embedded within the manifest
|
|
57
56
|
|
|
58
|
-
if self[
|
|
59
|
-
unless self[
|
|
60
|
-
m =
|
|
57
|
+
if self["structures"]
|
|
58
|
+
unless self["structures"].all? { |entry| entry.instance_of?(IIIF::V3::Presentation::Range) }
|
|
59
|
+
m = "All entries in the structures list must be a IIIF::V3::Presentation::Range"
|
|
61
60
|
raise IIIF::V3::Presentation::IllegalValueError, m
|
|
62
61
|
end
|
|
63
62
|
end
|
|
@@ -65,12 +64,12 @@ module IIIF
|
|
|
65
64
|
|
|
66
65
|
def validate_items_list(items_array)
|
|
67
66
|
unless items_array.size >= 1
|
|
68
|
-
m =
|
|
67
|
+
m = "The items list must have at least one entry (and it must be a IIIF::V3::Presentation::Canvas)"
|
|
69
68
|
raise IIIF::V3::Presentation::MissingRequiredKeyError, m
|
|
70
69
|
end
|
|
71
70
|
|
|
72
71
|
unless items_array.all? { |entry| entry.instance_of?(IIIF::V3::Presentation::Canvas) }
|
|
73
|
-
m =
|
|
72
|
+
m = "All entries in the items list must be a IIIF::V3::Presentation::Canvas"
|
|
74
73
|
raise IIIF::V3::Presentation::IllegalValueError, m
|
|
75
74
|
end
|
|
76
75
|
end
|