Skip to content
Snippets Groups Projects
Unverified Commit 82f70f8c authored by Chris Beer's avatar Chris Beer Committed by GitHub
Browse files

Merge pull request #1855 from ProjectMirador/1780-canvas-level-md

Add canvas (and manifest) level metadata
parents 25dfb2a3 30e3bfd1
No related branches found
No related tags found
No related merge requests found
Showing
with 478 additions and 97 deletions
/* global miradorInstance */
describe('Window Sidebars', () => {
beforeAll(async () => {
await page.goto('http://127.0.0.1:4488/__tests__/integration/mirador/');
});
it('renders and updates canvas level metadata', async () => {
await expect(page).toClick('#addBtn');
await expect(page).toFill('#manifestURL', 'http://localhost:5000/api/001');
await expect(page).toClick('#fetchBtn');
// TODO: Refactor the app so we get rid of the wait
await page.waitFor(1000);
await expect(page).toMatchElement('li', { text: 'http://localhost:5000/api/001' });
await expect(page).toClick('li button', { text: 'http://localhost:5000/api/001' });
await expect(page).toMatchElement(
'h3',
{ text: 'Bodleian Library Human Freaks 2 (33)' },
);
const windows = await page.evaluate(() => (
miradorInstance.store.getState().windows
));
const windowId = Object.values(windows)
.find(window => window.manifestId === 'http://localhost:5000/api/001')
.id;
await expect(page).toMatchElement(`#${windowId} button[aria-label="Toggle window sidebar"]`);
await expect(page).toClick(`#${windowId} button[aria-label="Toggle window sidebar"]`);
await expect(page).toMatchElement(`#${windowId} button[aria-label="Open information companion window"]`);
});
});
import React from 'react';
import { shallow } from 'enzyme';
import LabelValueMetadata from '../../../src/components/LabelValueMetadata';
describe('LabelValueMetadata', () => {
let wrapper;
let labelValuePair;
describe('when the labelValuePair has content', () => {
beforeEach(() => {
labelValuePair = [
{
label: 'Label 1',
value: 'Value 1',
},
{
label: 'Label 2',
value: 'Value 2',
},
];
wrapper = shallow(
<LabelValueMetadata labelValuePairs={labelValuePair} />,
);
});
it('renders a dt/dd for each label/value pair', () => {
expect(wrapper.find('dl').length).toEqual(1);
expect(wrapper.find('dt').length).toEqual(2);
expect(wrapper.find('dt').first().text()).toEqual('Label 1');
expect(wrapper.find('dt').last().text()).toEqual('Label 2');
expect(wrapper.find('dd').length).toEqual(2);
expect(wrapper.find('dd').first().text()).toEqual('Value 1');
expect(wrapper.find('dd').last().text()).toEqual('Value 2');
});
});
describe('when the labelValuePair has no content', () => {
beforeEach(() => {
labelValuePair = [];
wrapper = shallow(
<LabelValueMetadata labelValuePairs={labelValuePair} />,
);
});
it('renders an empty fragment instead of an empty dl', () => {
expect(wrapper.find('dl').length).toEqual(0);
expect(wrapper.matchesElement(<></>)).toBe(true);
});
});
});
import React from 'react'; import React from 'react';
import { shallow } from 'enzyme'; import { shallow } from 'enzyme';
import Typography from '@material-ui/core/Typography'; import Typography from '@material-ui/core/Typography';
import createStore from '../../../src/state/createStore';
import * as actions from '../../../src/state/actions';
import WindowSideBarInfoPanel from '../../../src/components/WindowSideBarInfoPanel'; import WindowSideBarInfoPanel from '../../../src/components/WindowSideBarInfoPanel';
import fixture from '../../fixtures/version-2/001.json'; import LabelValueMetadata from '../../../src/components/LabelValueMetadata';
describe('WindowSideBarInfoPanel', () => { describe('WindowSideBarInfoPanel', () => {
let wrapper; let wrapper;
let manifest;
const store = createStore();
describe('when metadata is present', () => {
beforeEach(() => { beforeEach(() => {
store.dispatch(actions.receiveManifest('foo', fixture));
manifest = store.getState().manifests.foo;
wrapper = shallow( wrapper = shallow(
<WindowSideBarInfoPanel manifest={manifest} />, <WindowSideBarInfoPanel
canvasLabel="The Canvas Label"
canvasDescription="The Canvas Description"
canvasMetadata={[{ label: {}, value: {} }]}
manifestLabel="The Manifest Label"
manifestDescription="The Manifest Description"
/>,
).dive(); ).dive();
}); });
it('renders without an error', () => { it('renders canvas level label, description, and metadata', () => {
expect( expect(
wrapper.find('WithStyles(Typography)[variant="h2"]').first().matchesElement( wrapper.find('WithStyles(Typography)[variant="h3"]').first().matchesElement(
<Typography>aboutThisItem</Typography>, <Typography>The Canvas Label</Typography>,
), ),
).toBe(true); ).toBe(true);
expect( expect(
wrapper.find('WithStyles(Typography)[variant="h3"]').first().matchesElement( wrapper.find('WithStyles(Typography)[variant="body2"]').first().matchesElement(
<Typography>Bodleian Library Human Freaks 2 (33)</Typography>, <Typography>The Canvas Description</Typography>,
),
).toBe(true);
expect(wrapper.find(LabelValueMetadata).length).toBe(2); // one for canvas one for manifest
});
it('renders manifest level label, description, and metadata', () => {
expect(
wrapper.find('WithStyles(Typography)[variant="h3"]').last().matchesElement(
<Typography>The Manifest Label</Typography>,
), ),
).toBe(true); ).toBe(true);
expect( expect(
wrapper.find('WithStyles(Typography)[variant="body2"]').first().matchesElement( wrapper.find('WithStyles(Typography)[variant="body2"]').last().matchesElement(
<Typography>[Handbill of Mr. Becket, [1787] ]</Typography>, <Typography>The Manifest Description</Typography>,
),
).toBe(true);
expect(wrapper.find(LabelValueMetadata).length).toBe(2); // one for canvas one for manifest
});
});
describe('when metadata is not present', () => {
beforeEach(() => {
wrapper = shallow(
<WindowSideBarInfoPanel />,
).dive();
});
it('does not render empty elements', () => {
expect(
wrapper.find('WithStyles(Typography)[variant="h2"]').first().matchesElement(
<Typography>aboutThisItem</Typography>,
), ),
).toBe(true); ).toBe(true);
expect(wrapper.find('WithStyles(Typography)[variant="h3"]').length).toEqual(0);
expect(wrapper.find('WithStyles(Typography)[variant="body2"]').length).toEqual(0);
});
}); });
}); });
import React from 'react'; import React from 'react';
import { shallow } from 'enzyme'; import { shallow } from 'enzyme';
import createStore from '../../../src/state/createStore';
import * as actions from '../../../src/state/actions';
import WindowSideBarPanel from '../../../src/components/WindowSideBarPanel'; import WindowSideBarPanel from '../../../src/components/WindowSideBarPanel';
import WindowSideBarInfoPanel from '../../../src/containers/WindowSideBarInfoPanel'; import WindowSideBarInfoPanel from '../../../src/containers/WindowSideBarInfoPanel';
import fixture from '../../fixtures/version-2/001.json';
describe('WindowSideBarPanel', () => { describe('WindowSideBarPanel', () => {
let wrapper; let wrapper;
let manifest;
const store = createStore();
beforeEach(() => {
store.dispatch(actions.receiveManifest('foo', fixture));
manifest = store.getState().manifests.foo;
});
describe('when the sideBarPanel is set to "info"', () => { describe('when the sideBarPanel is set to "info"', () => {
beforeEach(() => { beforeEach(() => {
wrapper = shallow(<WindowSideBarPanel sideBarPanel="info" manifest={manifest} />); wrapper = shallow(<WindowSideBarPanel windowId="abc123" sideBarPanel="info" />);
}); });
it('renders the WindowSideBarInfoPanel', () => { it('renders the WindowSideBarInfoPanel', () => {
...@@ -28,7 +18,7 @@ describe('WindowSideBarPanel', () => { ...@@ -28,7 +18,7 @@ describe('WindowSideBarPanel', () => {
describe('when the sideBarPanel is set to "closed" (or any other unknown value)', () => { describe('when the sideBarPanel is set to "closed" (or any other unknown value)', () => {
beforeEach(() => { beforeEach(() => {
wrapper = shallow(<WindowSideBarPanel sideBarPanel="closed" manifest={manifest} />); wrapper = shallow(<WindowSideBarPanel windowId="abc123" sideBarPanel="closed" />);
}); });
it('does not render any panel component', () => { it('does not render any panel component', () => {
......
import manifesto from 'manifesto.js'; import manifesto from 'manifesto.js';
import manifestFixture001 from '../../fixtures/version-2/001.json'; import manifestFixture001 from '../../fixtures/version-2/001.json';
import manifestFixture002 from '../../fixtures/version-2/002.json';
import manifestFixture019 from '../../fixtures/version-2/019.json';
import { import {
getCanvasLabel,
getDestructuredMetadata,
getSelectedCanvas,
getWindowManifest, getWindowManifest,
getManifestLogo, getManifestLogo,
getManifestCanvases, getManifestCanvases,
getManifestDescription,
getThumbnailNavigationPosition, getThumbnailNavigationPosition,
getManifestTitle, getManifestTitle,
getWindowViewType, getWindowViewType,
...@@ -139,3 +145,112 @@ describe('getWindowViewType', () => { ...@@ -139,3 +145,112 @@ describe('getWindowViewType', () => {
expect(received).toBeUndefined(); expect(received).toBeUndefined();
}); });
}); });
describe('getManifestDescription', () => {
it('should return manifest description', () => {
const manifest = { manifestation: manifesto.create(manifestFixture001) };
const received = getManifestDescription(manifest);
expect(received).toBe('[Handbill of Mr. Becket, [1787] ]');
});
it('should return undefined if manifest undefined', () => {
const received = getManifestDescription(undefined);
expect(received).toBeUndefined();
});
it('should return undefined if no manifestation', () => {
const manifest = {};
const received = getManifestDescription(manifest);
expect(received).toBeUndefined();
});
});
describe('getSelectedCanvas', () => {
const state = {
windows: {
a: {
id: 'a',
manifestId: 'x',
canvasIndex: 1,
},
},
manifests: {
x: {
id: 'x',
manifestation: manifesto.create(manifestFixture019),
},
},
};
const noManifestationState = {
windows: {
a: {
id: 'a',
manifestId: 'x',
canvasIndex: 1,
},
},
manifests: {
x: {
id: 'x',
},
},
};
it('should return canvas based on the canvas index stored window state', () => {
const selectedCanvas = getSelectedCanvas(state, 'a');
expect(selectedCanvas.id).toEqual(
'https://purl.stanford.edu/fr426cg9537/iiif/canvas/fr426cg9537_1',
);
});
it('should return an empty object when there is no manifestation to get a canvas from', () => {
const selectedCanvas = getSelectedCanvas(noManifestationState, 'a');
expect(selectedCanvas).toEqual({});
});
});
describe('getCanvasLabel', () => {
it('should return label of the canvas', () => {
const canvas = manifesto
.create(manifestFixture001)
.getSequences()[0]
.getCanvases()[0];
const received = getCanvasLabel(canvas);
expect(received).toBe('Whole Page');
});
it('should return the given canvas index (+1) if the canvas is undefined', () => {
expect(getCanvasLabel(undefined)).toBe(1);
expect(getCanvasLabel(undefined, 2)).toBe(3);
});
it('should return the canvas index (+1) if no manifestation', () => {
const canvas = { getLabel: () => {} };
const received = getCanvasLabel(canvas);
expect(received).toBe(1);
});
});
describe('getDestructuredMetadata', () => {
it('should return the first value of label/value attributes for each object in the array ', () => {
const iiifResource = manifesto.create(manifestFixture002);
const received = getDestructuredMetadata(iiifResource);
const expected = [{
label: 'date',
value: 'some date',
}];
expect(received).toEqual(expected);
});
it('returns an empty array if there is no metadata', () => {
const iiifResource = manifesto.create(manifestFixture019);
const received = getDestructuredMetadata(iiifResource);
expect(received).toEqual([]);
});
});
import React, { Component } from 'react';
import PropTypes from 'prop-types';
/**
* Renders label/value pair metadata in a dl
* @prop {object} labelValuePair
*/
class LabelValueMetadata extends Component {
/**
* render
* @return {String} - HTML markup for the component
*/
render() {
const { labelValuePairs } = this.props;
if (labelValuePairs.length === 0) {
return (<></>);
}
/* eslint-disable react/no-array-index-key */
// Disabling array index key for dt/dd elements as
// they are intended to display metadata that will not
// need to be re-rendered internally in any meaningful way
return (
<dl>
{labelValuePairs.reduce((acc, labelValuePair, i) => acc.concat([
<dt key={`label-${i}`}>{labelValuePair.label}</dt>,
<dd key={`value-${i}`}>{labelValuePair.value}</dd>,
]), [])}
</dl>
);
/* eslint-enable react/no-array-index-key */
}
}
LabelValueMetadata.propTypes = {
labelValuePairs: PropTypes.array.isRequired, // eslint-disable-line react/forbid-prop-types,
};
export default LabelValueMetadata;
...@@ -16,7 +16,7 @@ class Window extends Component { ...@@ -16,7 +16,7 @@ class Window extends Component {
render() { render() {
const { manifest, window } = this.props; const { manifest, window } = this.props;
return ( return (
<div className={ns('window')}> <div id={window.id} className={ns('window')}>
<WindowTopBar <WindowTopBar
windowId={window.id} windowId={window.id}
manifest={manifest} manifest={manifest}
......
...@@ -35,12 +35,7 @@ class WindowMiddleContent extends Component { ...@@ -35,12 +35,7 @@ class WindowMiddleContent extends Component {
const { manifest, window } = this.props; const { manifest, window } = this.props;
return ( return (
<div className={ns('window-middle-content')}> <div className={ns('window-middle-content')}>
<WindowSideBar <WindowSideBar windowId={window.id} />
windowId={window.id}
manifest={manifest}
sideBarOpen={window.sideBarOpen}
sideBarPanel={window.sideBarPanel}
/>
<CompanionWindow <CompanionWindow
windowId={window.id} windowId={window.id}
manifest={manifest} manifest={manifest}
......
...@@ -5,7 +5,7 @@ import Drawer from '@material-ui/core/Drawer'; ...@@ -5,7 +5,7 @@ import Drawer from '@material-ui/core/Drawer';
import { withStyles } from '@material-ui/core/styles'; import { withStyles } from '@material-ui/core/styles';
import List from '@material-ui/core/List'; import List from '@material-ui/core/List';
import WindowSideBarButtons from '../containers/WindowSideBarButtons'; import WindowSideBarButtons from '../containers/WindowSideBarButtons';
import WindowSideBarPanel from './WindowSideBarPanel'; import WindowSideBarPanel from '../containers/WindowSideBarPanel';
import ns from '../config/css-ns'; import ns from '../config/css-ns';
/** /**
...@@ -18,7 +18,7 @@ class WindowSideBar extends Component { ...@@ -18,7 +18,7 @@ class WindowSideBar extends Component {
*/ */
render() { render() {
const { const {
classes, manifest, windowId, sideBarOpen, sideBarPanel, classes, windowId, sideBarOpen, sideBarPanel,
} = this.props; } = this.props;
return ( return (
...@@ -38,7 +38,7 @@ class WindowSideBar extends Component { ...@@ -38,7 +38,7 @@ class WindowSideBar extends Component {
}} }}
> >
<List> <List>
<WindowSideBarButtons windowId={windowId} sideBarPanel={sideBarPanel} /> <WindowSideBarButtons windowId={windowId} />
</List> </List>
</Drawer> </Drawer>
<Drawer <Drawer
...@@ -55,11 +55,7 @@ class WindowSideBar extends Component { ...@@ -55,11 +55,7 @@ class WindowSideBar extends Component {
style: { position: 'absolute', width: '200px' }, style: { position: 'absolute', width: '200px' },
}} }}
> >
<WindowSideBarPanel <WindowSideBarPanel windowId={windowId} />
manifest={manifest}
windowId={windowId}
sideBarPanel={sideBarPanel}
/>
</Drawer> </Drawer>
</> </>
); );
...@@ -69,14 +65,12 @@ class WindowSideBar extends Component { ...@@ -69,14 +65,12 @@ class WindowSideBar extends Component {
WindowSideBar.propTypes = { WindowSideBar.propTypes = {
classes: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types, classes: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types,
manifest: PropTypes.object, // eslint-disable-line react/forbid-prop-types
windowId: PropTypes.string.isRequired, windowId: PropTypes.string.isRequired,
sideBarOpen: PropTypes.bool, sideBarOpen: PropTypes.bool,
sideBarPanel: PropTypes.string, sideBarPanel: PropTypes.string,
}; };
WindowSideBar.defaultProps = { WindowSideBar.defaultProps = {
manifest: {},
sideBarOpen: false, sideBarOpen: false,
sideBarPanel: 'closed', sideBarPanel: 'closed',
}; };
......
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import Divider from '@material-ui/core/Divider';
import Typography from '@material-ui/core/Typography'; import Typography from '@material-ui/core/Typography';
import { withStyles } from '@material-ui/core/styles'; import { withStyles } from '@material-ui/core/styles';
import LabelValueMetadata from './LabelValueMetadata';
import ns from '../config/css-ns'; import ns from '../config/css-ns';
/** /**
* WindowSideBarInfoPanel * WindowSideBarInfoPanel
*/ */
class WindowSideBarInfoPanel extends Component { class WindowSideBarInfoPanel extends Component {
/**
* manifestLabel - get the label from the manifesto manifestation
* @return String
*/
manifestLabel() {
const { manifest } = this.props;
if (manifest.manifestation) {
return manifest.manifestation.getLabel().map(label => label.value)[0];
}
return '';
}
/**
* manifestDescription - get the description from the manifesto manifestation
* @return String
*/
manifestDescription() {
const { manifest } = this.props;
if (manifest.manifestation) {
return manifest.manifestation.getDescription().map(label => label.value);
}
return '';
}
/** /**
* render * render
* @return * @return
*/ */
render() { render() {
const { classes, t } = this.props; const {
canvasDescription,
canvasLabel,
canvasMetadata,
classes,
manifestDescription,
manifestLabel,
manifestMetadata,
t,
} = this.props;
return ( return (
<div className={ns('window-sidebar-info-panel')}> <div className={ns('window-sidebar-info-panel')}>
<Typography variant="h2" className={classes.windowSideBarH2}>{t('aboutThisItem')}</Typography> <Typography variant="h2" className={classes.windowSideBarH2}>{t('aboutThisItem')}</Typography>
<Typography variant="h3" className={classes.windowSideBarH3}>{this.manifestLabel()}</Typography> {canvasLabel && <Typography variant="h3" className={classes.windowSideBarH3}>{canvasLabel}</Typography>}
<Typography variant="body2">{this.manifestDescription()}</Typography> {canvasDescription && <Typography variant="body2">{canvasDescription}</Typography>}
{canvasMetadata && <LabelValueMetadata labelValuePairs={canvasMetadata} />}
<Divider />
{manifestLabel && <Typography variant="h3" className={classes.windowSideBarH3}>{manifestLabel}</Typography>}
{manifestDescription && <Typography variant="body2">{manifestDescription}</Typography>}
{manifestMetadata && <LabelValueMetadata labelValuePairs={manifestMetadata} />}
</div> </div>
); );
} }
} }
WindowSideBarInfoPanel.propTypes = { WindowSideBarInfoPanel.propTypes = {
canvasDescription: PropTypes.string,
canvasLabel: PropTypes.string,
canvasMetadata: PropTypes.array, // eslint-disable-line react/forbid-prop-types
classes: PropTypes.object, // eslint-disable-line react/forbid-prop-types classes: PropTypes.object, // eslint-disable-line react/forbid-prop-types
manifest: PropTypes.object, // eslint-disable-line react/forbid-prop-types manifestLabel: PropTypes.string,
manifestDescription: PropTypes.string,
manifestMetadata: PropTypes.array, // eslint-disable-line react/forbid-prop-types
t: PropTypes.func, t: PropTypes.func,
}; };
WindowSideBarInfoPanel.defaultProps = { WindowSideBarInfoPanel.defaultProps = {
canvasDescription: null,
canvasLabel: null,
canvasMetadata: [],
classes: {}, classes: {},
manifest: {}, manifestLabel: null,
manifestDescription: null,
manifestMetadata: [],
t: key => key, t: key => key,
}; };
......
...@@ -12,10 +12,10 @@ class WindowSideBarPanel extends Component { ...@@ -12,10 +12,10 @@ class WindowSideBarPanel extends Component {
* @return React Component * @return React Component
*/ */
activePanelComponent() { activePanelComponent() {
const { manifest, sideBarPanel } = this.props; const { windowId, sideBarPanel } = this.props;
switch (sideBarPanel) { switch (sideBarPanel) {
case 'info': case 'info':
return <WindowSideBarInfoPanel manifest={manifest} />; return <WindowSideBarInfoPanel windowId={windowId} />;
default: default:
return null; return null;
} }
...@@ -35,11 +35,10 @@ class WindowSideBarPanel extends Component { ...@@ -35,11 +35,10 @@ class WindowSideBarPanel extends Component {
} }
WindowSideBarPanel.propTypes = { WindowSideBarPanel.propTypes = {
manifest: PropTypes.object, // eslint-disable-line react/forbid-prop-types
sideBarPanel: PropTypes.string, sideBarPanel: PropTypes.string,
windowId: PropTypes.string.isRequired,
}; };
WindowSideBarPanel.defaultProps = { WindowSideBarPanel.defaultProps = {
manifest: {},
sideBarPanel: 'closed', // Closed will fall out to the default null case for the actiuve panel sideBarPanel: 'closed', // Closed will fall out to the default null case for the actiuve panel
}; };
......
import { connect } from 'react-redux';
import { compose } from 'redux';
import miradorWithPlugins from '../lib/miradorWithPlugins'; import miradorWithPlugins from '../lib/miradorWithPlugins';
import WindowSideBar from '../components/WindowSideBar'; import WindowSideBar from '../components/WindowSideBar';
export default miradorWithPlugins(WindowSideBar); /**
* mapStateToProps - to hook up connect
* @memberof WindowSideBar
* @private
*/
const mapStateToProps = (state, props) => (
{
sideBarOpen: state.windows[props.windowId].sideBarOpen,
sideBarPanel: state.windows[props.windowId].sideBarPanel,
}
);
const enhance = compose(
connect(mapStateToProps, null),
miradorWithPlugins,
// further HOC
);
export default enhance(WindowSideBar);
...@@ -17,8 +17,19 @@ const mapDispatchToProps = (dispatch, props) => ({ ...@@ -17,8 +17,19 @@ const mapDispatchToProps = (dispatch, props) => ({
), ),
}); });
/**
* mapStateToProps - used to hook up connect to state
* @memberof WindowSideButtons
* @private
*/
const mapStateToProps = (state, { windowId }) => ({
sideBarPanel: state.windows[windowId].sideBarPanel,
});
const enhance = compose( const enhance = compose(
connect(null, mapDispatchToProps), connect(mapStateToProps, mapDispatchToProps),
miradorWithPlugins, miradorWithPlugins,
withNamespaces(), withNamespaces(),
// further HOC go here // further HOC go here
......
import { compose } from 'redux'; import { compose } from 'redux';
import { connect } from 'react-redux';
import { withNamespaces } from 'react-i18next'; import { withNamespaces } from 'react-i18next';
import miradorWithPlugins from '../lib/miradorWithPlugins'; import miradorWithPlugins from '../lib/miradorWithPlugins';
import {
getDestructuredMetadata,
getCanvasLabel,
getManifestDescription,
getManifestTitle,
getSelectedCanvas,
getWindowManifest,
} from '../state/selectors';
import WindowSideBarInfoPanel from '../components/WindowSideBarInfoPanel'; import WindowSideBarInfoPanel from '../components/WindowSideBarInfoPanel';
/**
* mapStateToProps - to hook up connect
* @memberof WindowSideBarInfoPanel
* @private
*/
const mapStateToProps = (state, { windowId }) => ({
canvasLabel: getCanvasLabel(
getSelectedCanvas(state, windowId),
state.windows[windowId].canvasIndex,
),
canvasDescription: getSelectedCanvas(state, windowId).getProperty('description'),
canvasMetadata: getDestructuredMetadata(getSelectedCanvas(state, windowId)),
manifestLabel: getManifestTitle(getWindowManifest(state, windowId)),
manifestDescription: getManifestDescription(getWindowManifest(state, windowId)),
manifestMetadata: getDestructuredMetadata(getWindowManifest(state, windowId).manifestation),
});
const enhance = compose( const enhance = compose(
connect(mapStateToProps, null),
withNamespaces(), withNamespaces(),
miradorWithPlugins, miradorWithPlugins,
// further HOC // further HOC
......
import { connect } from 'react-redux';
import { compose } from 'redux';
import miradorWithPlugins from '../lib/miradorWithPlugins'; import miradorWithPlugins from '../lib/miradorWithPlugins';
import WindowSideBarPanel from '../components/WindowSideBarPanel'; import WindowSideBarPanel from '../components/WindowSideBarPanel';
export default miradorWithPlugins(WindowSideBarPanel); /** */
const mapStateToProps = (state, { windowId }) => ({
sideBarPanel: state.windows[windowId].sideBarPanel,
});
export default compose(
connect(mapStateToProps, null),
miradorWithPlugins,
// further HOC
)(WindowSideBarPanel);
...@@ -34,6 +34,24 @@ export function getManifestCanvases(manifest) { ...@@ -34,6 +34,24 @@ export function getManifestCanvases(manifest) {
return manifest.manifestation.getSequences()[0].getCanvases(); return manifest.manifestation.getSequences()[0].getCanvases();
} }
/**
* Return the current canvas selected in a window
* @param {object} state
* @param {String} windowId
* @return {Object}
*/
export function getSelectedCanvas(state, windowId) {
const manifest = getWindowManifest(state, windowId);
const { canvasIndex } = state.windows[windowId];
if (!manifest.manifestation) {
return {};
}
return manifest.manifestation.getSequences()[0].getCanvasByIndex(canvasIndex);
}
/** Return position of thumbnail navigation in a certain window. /** Return position of thumbnail navigation in a certain window.
* @param {object} state * @param {object} state
* @param {String} windowId * @param {String} windowId
...@@ -63,3 +81,44 @@ export function getManifestTitle(manifest) { ...@@ -63,3 +81,44 @@ export function getManifestTitle(manifest) {
export function getWindowViewType(state, windowId) { export function getWindowViewType(state, windowId) {
return state.windows[windowId] && state.windows[windowId].view; return state.windows[windowId] && state.windows[windowId].view;
} }
/**
* Return manifest description
* @param {object} manifest
* @return {String}
*/
export function getManifestDescription(manifest) {
return manifest
&& manifest.manifestation
&& manifest.manifestation.getDescription().map(label => label.value)[0];
}
/**
* Return canvas label, or alternatively return the given index + 1 to be displayed
* @param {object} canvas
* @return {String|Integer}
*/
export function getCanvasLabel(canvas, canvasIndex) {
return (canvas
&& canvas.getLabel()
&& canvas.getLabel().map(label => label.value)[0])
|| (canvasIndex || 0) + 1;
}
/**
* Return canvas metadata in a label / value structure
* This is a potential seam for pulling the i18n locale from
* state and plucking out the appropriate language.
* For now we're just getting the first.
* @param {object} IIIF Resource
* @return {Array[Object]}
*/
export function getDestructuredMetadata(iiifResoruce) {
return (iiifResoruce
&& iiifResoruce.getMetadata()
&& iiifResoruce.getMetadata().map(resource => ({
label: resource.label[0].value,
value: resource.value[0].value,
}))
);
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment