diff --git a/__tests__/fixtures/version-2/related.json b/__tests__/fixtures/version-2/related.json
new file mode 100644
index 0000000000..f87bf96636
--- /dev/null
+++ b/__tests__/fixtures/version-2/related.json
@@ -0,0 +1,16 @@
+{
+ "@context": "http://iiif.io/api/presentation/2/context.json",
+ "@id": "http://example.com/iiif/manifest/related-urls.json",
+ "@type": "sc:Manifest",
+ "related": [
+ "http://example.com/related1",
+ {
+ "@id": "http://example.com/related2"
+ },
+ {
+ "@id": "http://example.com/related3",
+ "format": "text/html",
+ "label": "Something related"
+ }
+ ]
+}
diff --git a/__tests__/src/components/ManifestRelatedLinks.test.js b/__tests__/src/components/ManifestRelatedLinks.test.js
index 234b5bab99..4bf7994f71 100644
--- a/__tests__/src/components/ManifestRelatedLinks.test.js
+++ b/__tests__/src/components/ManifestRelatedLinks.test.js
@@ -21,6 +21,16 @@ describe('ManifestRelatedLinks', () => {
},
]}
manifestUrl="http://example.com/"
+ related={[
+ {
+ value: 'http://example.com/related',
+ },
+ {
+ format: 'video/ogg',
+ label: 'Video',
+ value: 'http://example.com/video',
+ },
+ ]}
renderings={[
{
label: 'PDF Version',
@@ -81,16 +91,42 @@ describe('ManifestRelatedLinks', () => {
).toBe(true);
});
- it('renders manifest seeAlso information', () => {
+ it('renders related information', () => {
expect(
wrapper.find(Typography).at(5)
.matchesElement(
- iiif_seeAlso,
+ iiif_related,
),
).toBe(true);
expect(
wrapper.find(Typography).at(6)
+ .matchesElement(
+ http://example.com/related,
+ ),
+ ).toBe(true);
+
+ expect(
+ wrapper.find(Typography).at(7)
+ .matchesElement(
+
+ Video
+ (video/ogg)
+ ,
+ ),
+ ).toBe(true);
+ });
+
+ it('renders manifest seeAlso information', () => {
+ expect(
+ wrapper.find(Typography).at(9)
+ .matchesElement(
+ iiif_seeAlso,
+ ),
+ ).toBe(true);
+
+ expect(
+ wrapper.find(Typography).at(10)
.matchesElement(
A
@@ -100,7 +136,7 @@ describe('ManifestRelatedLinks', () => {
).toBe(true);
expect(
- wrapper.find(Typography).at(8)
+ wrapper.find(Typography).at(12)
.matchesElement(
http://example.com/b,
),
@@ -109,14 +145,14 @@ describe('ManifestRelatedLinks', () => {
it('renders manifest links', () => {
expect(
- wrapper.find(Typography).at(9)
+ wrapper.find(Typography).at(13)
.matchesElement(
iiif_manifest,
),
).toBe(true);
expect(
- wrapper.find(Typography).at(10)
+ wrapper.find(Typography).at(14)
.matchesElement(
http://example.com/,
),
diff --git a/__tests__/src/selectors/manifests.test.js b/__tests__/src/selectors/manifests.test.js
index 3c174506f3..28b0461ad5 100644
--- a/__tests__/src/selectors/manifests.test.js
+++ b/__tests__/src/selectors/manifests.test.js
@@ -6,6 +6,7 @@ import manifestFixtureSn904cj3429 from '../../fixtures/version-2/sn904cj3429.jso
import manifestFixturev3001 from '../../fixtures/version-3/001.json';
import manifestFixtureWithAProvider from '../../fixtures/version-3/with_a_provider.json';
import manifestFixtureFg165hz3589 from '../../fixtures/version-2/fg165hz3589.json';
+import manifestFixtureRelated from '../../fixtures/version-2/related.json';
import {
getManifestoInstance,
getManifestLocale,
@@ -18,8 +19,10 @@ import {
getManifestTitle,
getManifestThumbnail,
getManifestMetadata,
+ getManifestRelated,
getManifestRelatedContent,
getManifestRenderings,
+ getManifestSeeAlso,
getManifestUrl,
getMetadataLocales,
getRequiredStatement,
@@ -210,6 +213,33 @@ describe('getManifestRenderings', () => {
});
});
+describe('getManifestRelated', () => {
+ it('should return manifest related', () => {
+ const state = { manifests: { x: { json: manifestFixtureRelated } } };
+ const received = getManifestRelated(state, { manifestId: 'x' });
+ expect(received).toEqual([
+ {
+ value: 'http://example.com/related1',
+ },
+ {
+ format: undefined,
+ label: null,
+ value: 'http://example.com/related2',
+ },
+ {
+ format: 'text/html',
+ label: 'Something related',
+ value: 'http://example.com/related3',
+ },
+ ]);
+ });
+
+ it('should return undefined if manifest undefined', () => {
+ const received = getManifestRelated({ manifests: {} }, { manifestId: 'x' });
+ expect(received).toBeUndefined();
+ });
+});
+
describe('getManifestRelatedContent', () => {
it('should return manifest seeAlso content', () => {
const state = { manifests: { x: { json: manifestFixtureSn904cj3429 } } };
@@ -229,6 +259,25 @@ describe('getManifestRelatedContent', () => {
});
});
+describe('getManifestSeeAlso', () => {
+ it('should return manifest seeAlso content', () => {
+ const state = { manifests: { x: { json: manifestFixtureSn904cj3429 } } };
+ const received = getManifestSeeAlso(state, { manifestId: 'x' });
+ expect(received).toEqual([
+ {
+ format: 'application/mods+xml',
+ label: null,
+ value: 'https://purl.stanford.edu/sn904cj3429.mods',
+ },
+ ]);
+ });
+
+ it('should return undefined if manifest undefined', () => {
+ const received = getManifestSeeAlso({ manifests: {} }, { manifestId: 'x' });
+ expect(received).toBeUndefined();
+ });
+});
+
describe('getManifestUrl', () => {
it('should return manifest url', () => {
const state = { manifests: { x: { json: manifestFixtureWithAProvider } } };
diff --git a/src/components/ManifestRelatedLinks.js b/src/components/ManifestRelatedLinks.js
index 533b4522d1..943d287ff3 100644
--- a/src/components/ManifestRelatedLinks.js
+++ b/src/components/ManifestRelatedLinks.js
@@ -20,6 +20,7 @@ export class ManifestRelatedLinks extends Component {
classes,
homepage,
manifestUrl,
+ related,
renderings,
seeAlso,
id,
@@ -68,17 +69,34 @@ export class ManifestRelatedLinks extends Component {
}
>
)}
+ { related && (
+ <>
+ {t('iiif_related')}
+ {
+ related.map(relatedItem => (
+
+
+ {relatedItem.label || relatedItem.value}
+
+ { relatedItem.format && (
+ {` (${relatedItem.format})`}
+ )}
+
+ ))
+ }
+ >
+ )}
{ seeAlso && (
<>
{t('iiif_seeAlso')}
{
- seeAlso.map(related => (
-
-
- {related.label || related.value}
+ seeAlso.map(seeAlsoItem => (
+
+
+ {seeAlsoItem.label || seeAlsoItem.value}
- { related.format && (
- {` (${related.format})`}
+ { seeAlsoItem.format && (
+ {` (${seeAlsoItem.format})`}
)}
))
@@ -110,6 +128,11 @@ ManifestRelatedLinks.propTypes = {
})),
id: PropTypes.string.isRequired,
manifestUrl: PropTypes.string,
+ related: PropTypes.arrayOf(PropTypes.shape({
+ format: PropTypes.string,
+ label: PropTypes.string,
+ value: PropTypes.string,
+ })),
renderings: PropTypes.arrayOf(PropTypes.shape({
label: PropTypes.string,
value: PropTypes.string,
@@ -125,6 +148,7 @@ ManifestRelatedLinks.propTypes = {
ManifestRelatedLinks.defaultProps = {
homepage: null,
manifestUrl: null,
+ related: null,
renderings: null,
seeAlso: null,
t: key => key,
diff --git a/src/containers/ManifestRelatedLinks.js b/src/containers/ManifestRelatedLinks.js
index 005029f220..6bcc356778 100644
--- a/src/containers/ManifestRelatedLinks.js
+++ b/src/containers/ManifestRelatedLinks.js
@@ -5,8 +5,9 @@ import { withStyles } from '@material-ui/core/styles';
import { withPlugins } from '../extend/withPlugins';
import {
getManifestHomepage,
- getManifestRelatedContent,
+ getManifestRelated,
getManifestRenderings,
+ getManifestSeeAlso,
getManifestUrl,
} from '../state/selectors';
import { ManifestRelatedLinks } from '../components/ManifestRelatedLinks';
@@ -19,8 +20,9 @@ import { ManifestRelatedLinks } from '../components/ManifestRelatedLinks';
const mapStateToProps = (state, { id, windowId }) => ({
homepage: getManifestHomepage(state, { windowId }),
manifestUrl: getManifestUrl(state, { windowId }),
+ related: getManifestRelated(state, { windowId }),
renderings: getManifestRenderings(state, { windowId }),
- seeAlso: getManifestRelatedContent(state, { windowId }),
+ seeAlso: getManifestSeeAlso(state, { windowId }),
});
const styles = {
diff --git a/src/locales/de/translation.json b/src/locales/de/translation.json
index ebc6b43fcc..e732a7d2d2 100644
--- a/src/locales/de/translation.json
+++ b/src/locales/de/translation.json
@@ -59,6 +59,7 @@
"hideZoomControls": "Zoomsteuerung verbergen",
"iiif_homepage": "Über diese Ressource",
"iiif_manifest": "IIIF-Manifest",
+ "iiif_related": "Verwandtes",
"iiif_renderings": "Alternative Formate",
"iiif_seeAlso": "Siehe auch",
"import" : "Importieren",
diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json
index b5102f3149..18878e9cbc 100644
--- a/src/locales/en/translation.json
+++ b/src/locales/en/translation.json
@@ -61,6 +61,7 @@
"hideZoomControls": "Hide zoom controls",
"iiif_homepage": "About this resource",
"iiif_manifest": "IIIF manifest",
+ "iiif_related": "Related",
"iiif_renderings": "Alternate formats",
"iiif_seeAlso": "See also",
"import" : "Import",
diff --git a/src/state/selectors/manifests.js b/src/state/selectors/manifests.js
index b42eb27396..51e82c2851 100644
--- a/src/state/selectors/manifests.js
+++ b/src/state/selectors/manifests.js
@@ -153,13 +153,14 @@ export const getManifestRenderings = createSelector(
/**
* Return the IIIF v2/v3 seeAlso data from a manifest or null
+*
* @param {object} state
* @param {object} props
* @param {string} props.manifestId
* @param {string} props.windowId
* @return {String|null}
*/
-export const getManifestRelatedContent = createSelector(
+export const getManifestSeeAlso = createSelector(
[
getProperty('seeAlso'),
getManifestLocale,
@@ -175,6 +176,48 @@ export const getManifestRelatedContent = createSelector(
)),
);
+/**
+* Return the IIIF v2/v3 seeAlso data from a manifest or null
+*
+* @param {object} state
+* @param {object} props
+* @param {string} props.manifestId
+* @param {string} props.windowId
+* @return {String|null}
+* @deprecated This does not actually return the content of "related" and
+* might be removed in a future version.
+* @see getManifestSeeAlso
+*/
+export const getManifestRelatedContent = getManifestSeeAlso;
+
+/**
+* Return the IIIF v2 realated links manifest or null
+* @param {object} state
+* @param {object} props
+* @param {string} props.manifestId
+* @param {string} props.windowId
+* @return {String|null}
+*/
+export const getManifestRelated = createSelector(
+ [
+ getProperty('related'),
+ getManifestLocale,
+ ],
+ (relatedLinks, locale) => relatedLinks
+ && asArray(relatedLinks).map(related => (
+ typeof related === 'string'
+ ? {
+ value: related,
+ }
+ : {
+ format: related.format,
+ label: PropertyValue.parse(related.label, locale)
+ .getValue(),
+ value: related.id || related['@id'],
+ }
+ )),
+);
+
/**
* Return the IIIF requiredStatement (v3) or attribution (v2) data from a manifest or null
* @param {object} state