diff --git a/src/Canvas.ts b/src/Canvas.ts index 88228ab1..860c07d3 100644 --- a/src/Canvas.ts +++ b/src/Canvas.ts @@ -135,8 +135,23 @@ export class Canvas extends Resource { return maxDimensions; } - // Presentation API 3.0 - getContent(): Annotation[] { + /** + * Return first annotation page of content. + */ + getContent(): Annotation[]; + + /** + * Get content by index of annotation page + * @param index + */ + getContent(index: number): Annotation[]; + + /** + * Get canvas content by Identifier on Annotation Page + * @param pageId + */ + getContent(pageId: string): Annotation[]; + getContent(index: string | number = 0): Annotation[] { const content: Annotation[] = []; const items = this.__jsonld.items || this.__jsonld.content; @@ -146,8 +161,13 @@ export class Canvas extends Resource { // should be contained in an AnnotationPage let annotationPage: AnnotationPage | null = null; + const page = + typeof index === "string" + ? this.getAnnotationPageIndexById(index, 0) + : index; + if (items.length) { - annotationPage = new AnnotationPage(items[0], this.options); + annotationPage = new AnnotationPage(items[page], this.options); } if (!annotationPage) { @@ -165,6 +185,35 @@ export class Canvas extends Resource { return content; } + /** + * Returns the index of the annotation page given an ID. + * + * @param pageId + */ + getAnnotationPageIndexById(pageId: string): number | undefined; + getAnnotationPageIndexById(pageId: string, defaultIndex: number): number; + getAnnotationPageIndexById( + pageId: string, + defaultIndex?: number + ): number | undefined { + const items = this.__jsonld.items || this.__jsonld.content; + if (!items || items.length === 0) { + return defaultIndex; + } + + for (let index = 0; index < items.length; index++) { + if (items[index].id && items[index].id === pageId) { + return index; + } + } + + return defaultIndex; + } + + getAnnotationTotalPages(): number { + return (this.__jsonld.items || this.__jsonld.content || []).length; + } + getDuration(): number | null { return this.getProperty("duration"); } diff --git a/test/fixtures/manifests.js b/test/fixtures/manifests.js index ba63dd00..c4818692 100644 --- a/test/fixtures/manifests.js +++ b/test/fixtures/manifests.js @@ -56,7 +56,8 @@ module.exports = { "witnesstopeter": "http://localhost:3001/witnesstopeter.json", "wunder": "http://localhost:3001/wunder.json", "deephierarchytop": "http://localhost:3001/deephierarchytop.json", - "sctagracilis": "http://localhost:3001/sctagracilis.json" + "sctagracilis": "http://localhost:3001/sctagracilis.json", + "pres3MultiAnnotationPages": "http://localhost:3001/pres3-manifest-multi-annotation-pages.json", //"query-bodleian": "http://iiif.bodleian.ox.ac.uk/iiif/manifest/f22e9dae-c070-48eb-be0b-aa6c5bc195a6.json", //"query-gams": "http://gams.uni-graz.at/cocoon/mets2json?source=http%3A%2F%2Fgams.uni-graz.at%2Farchive%2Fget%2Fo%3Asrbas.1535%2FMETS_SOURCE" }; diff --git a/test/fixtures/pres3-manifest-multi-annotation-pages.json b/test/fixtures/pres3-manifest-multi-annotation-pages.json new file mode 100644 index 00000000..176c9a61 --- /dev/null +++ b/test/fixtures/pres3-manifest-multi-annotation-pages.json @@ -0,0 +1,165 @@ +{ + "@context": "http://iiif.io/api/presentation/3/context.json", + "id": "https://iiif.io/api/cookbook/recipe/0064-opera-one-canvas/manifest.json", + "type": "Manifest", + "label": { + "it": [ + "L'Elisir D'Amore" + ], + "en": [ + "The Elixir of Love" + ] + }, + "metadata": [ + { + "label": { + "en": [ + "Date Issued" + ] + }, + "value": { + "en": [ + "2019" + ] + } + }, + { + "label": { + "en": [ + "Publisher" + ] + }, + "value": { + "en": [ + "Indiana University Jacobs School of Music" + ] + } + } + ], + "items": [ + { + "id": "https://iiif.io/api/cookbook/recipe/0064-opera-one-canvas/canvas/1", + "type": "Canvas", + "width": 1920, + "height": 1080, + "duration": 7278.422, + "items": [ + { + "id": "https://iiif.io/api/cookbook/recipe/0064-opera-one-canvas/canvas/1/annotation_page/1", + "type": "AnnotationPage", + "items": [ + { + "id": "https://iiif.io/api/cookbook/recipe/0064-opera-one-canvas/canvas/1/annotation_page/1/annotation/1", + "type": "Annotation", + "motivation": "painting", + "target": "https://iiif.io/api/cookbook/recipe/0064-opera-one-canvas/canvas/1#t=0", + "body": { + "id": "https://fixtures.iiif.io/video/indiana/donizetti-elixir/vae0637_accessH264_low.mp4", + "type": "Video", + "format": "video/mp4", + "height": 1080, + "width": 1920, + "duration": 3971.24 + } + } + ] + }, + { + "id": "https://iiif.io/api/cookbook/recipe/0064-opera-one-canvas/canvas/1/annotation_page/2", + "type": "AnnotationPage", + "items": [ + { + "id": "https://iiif.io/api/cookbook/recipe/0064-opera-one-canvas/canvas/1/annotation_page/1/annotation/2", + "type": "Annotation", + "motivation": "painting", + "target": "https://iiif.io/api/cookbook/recipe/0064-opera-one-canvas/canvas/1#t=3971.24", + "body": { + "id": "https://fixtures.iiif.io/video/indiana/donizetti-elixir/vae0637_accessH264_low_act_2.mp4", + "type": "Video", + "format": "video/mp4", + "height": 1080, + "width": 1920, + "duration": 3307.22 + } + } + ] + } + ], + "thumbnail": [ + { + "id": "https://fixtures.iiif.io/video/indiana/donizetti-elixir/act1-thumbnail.png", + "type": "Image" + } + ] + } + ], + "structures": [ + { + "type": "Range", + "id": "https://iiif.io/api/cookbook/recipe/0064-opera-one-canvas/range/1", + "label": { + "it": [ + "Gaetano Donizetti, L'Elisir D'Amore" + ] + }, + "items": [ + { + "type": "Range", + "id": "https://iiif.io/api/cookbook/recipe/0064-opera-one-canvas/range/2", + "label": { + "it": [ + "Atto Primo" + ] + }, + "items": [ + { + "type": "Range", + "id": "https://iiif.io/api/cookbook/recipe/0064-opera-one-canvas/range/3", + "label": { + "it": [ + "Preludio e Coro d'introduzione – Bel conforto al mietitore" + ] + }, + "items": [ + { + "type": "Canvas", + "id": "https://iiif.io/api/cookbook/recipe/0064-opera-one-canvas/canvas/1#t=0,302.05" + } + ] + }, + { + "type": "Range", + "id": "https://iiif.io/api/cookbook/recipe/0064-opera-one-canvas/range/4", + "label": { + "en": [ + "Remainder of Atto Primo" + ] + }, + "items": [ + { + "type": "Canvas", + "id": "https://iiif.io/api/cookbook/recipe/0064-opera-one-canvas/canvas/1#t=302.05,3971.24" + } + ] + } + ] + }, + { + "type": "Range", + "id": "https://iiif.io/api/cookbook/recipe/0064-opera-one-canvas/range/5", + "label": { + "it": [ + "Atto Secondo" + ] + }, + "items": [ + { + "type": "Canvas", + "id": "https://iiif.io/api/cookbook/recipe/0064-opera-one-canvas/canvas/1#t=3971.24,7278.422" + } + ] + } + ] + } + ] +} diff --git a/test/index.js b/test/index.js index bf192dbe..32ec10f9 100644 --- a/test/index.js +++ b/test/index.js @@ -70,6 +70,7 @@ importTest('pres3-collection', './tests/pres3-collection'); importTest('pres3-collection2', './tests/pres3-collection2'); importTest('pres3-collection3', './tests/pres3-collection3'); importTest('pres3-collection4', './tests/pres3-collection4'); +importTest('pres3-multiple-annotation-pages', './tests/pres3-multiple-annotation-pages'); importTest('pres3-pdf', './tests/pres3-pdf'); importTest('pres3', './tests/pres3'); importTest('presentation2-paging', './tests/presentation2-paging'); diff --git a/test/tests/pres3-multiple-annotation-pages.js b/test/tests/pres3-multiple-annotation-pages.js new file mode 100644 index 00000000..d466ab3a --- /dev/null +++ b/test/tests/pres3-multiple-annotation-pages.js @@ -0,0 +1,42 @@ +var expect = require('chai').expect; +var should = require('chai').should(); +var manifesto = require('../../dist-commonjs/'); +var manifests = require('../fixtures/manifests'); + +var manifest, canvas; + +describe('presentation 3 - multiple annotation pages', function() { + + it('loads successfully', function(done) { + manifesto.loadManifest(manifests.pres3MultiAnnotationPages).then(function(data) { + manifest = manifesto.parseManifest(data); + canvas = manifest.getSequenceByIndex(0).getCanvasByIndex(0); + done(); + }); + }); + + it('has correct total for annotation pages', function() { + + expect(canvas.getAnnotationTotalPages()).to.equal(2); + }); + + it('can access first and second pages', () => { + const firstPage = canvas.getAnnotationPageIndexById('https://iiif.io/api/cookbook/recipe/0064-opera-one-canvas/canvas/1/annotation_page/1'); + expect(firstPage).to.equal(0); + + const secondPage = canvas.getAnnotationPageIndexById('https://iiif.io/api/cookbook/recipe/0064-opera-one-canvas/canvas/1/annotation_page/2'); + expect(secondPage).to.equal(1); + }) + + it('create annotation pages correctly', () => { + const firstPage = canvas.getContent('https://iiif.io/api/cookbook/recipe/0064-opera-one-canvas/canvas/1/annotation_page/1'); + expect(firstPage).to.have.lengthOf(1); + expect(firstPage[0].id).to.equal('https://iiif.io/api/cookbook/recipe/0064-opera-one-canvas/canvas/1/annotation_page/1/annotation/1'); + + const secondPage = canvas.getContent('https://iiif.io/api/cookbook/recipe/0064-opera-one-canvas/canvas/1/annotation_page/2'); + expect(secondPage).to.have.lengthOf(1); + expect(secondPage[0].id).to.equal('https://iiif.io/api/cookbook/recipe/0064-opera-one-canvas/canvas/1/annotation_page/1/annotation/2'); + }) + +}); +