Skip to content
Snippets Groups Projects
Commit 22e08a79 authored by Chris Beer's avatar Chris Beer
Browse files

Add a TOC view to the canvas panel; fixes #2068

parent 07c86854
No related branches found
No related tags found
No related merge requests found
...@@ -3,6 +3,8 @@ import { shallow } from 'enzyme'; ...@@ -3,6 +3,8 @@ import { shallow } from 'enzyme';
import List from '@material-ui/core/List'; import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem'; import ListItem from '@material-ui/core/ListItem';
import Typography from '@material-ui/core/Typography'; import Typography from '@material-ui/core/Typography';
import ExpansionPanel from '@material-ui/core/ExpansionPanel';
import ExpansionPanelSummary from '@material-ui/core/ExpansionPanelSummary';
import manifesto from 'manifesto.js'; import manifesto from 'manifesto.js';
import { WindowSideBarCanvasPanel } from '../../../src/components/WindowSideBarCanvasPanel'; import { WindowSideBarCanvasPanel } from '../../../src/components/WindowSideBarCanvasPanel';
import { CanvasThumbnail } from '../../../src/components/CanvasThumbnail'; import { CanvasThumbnail } from '../../../src/components/CanvasThumbnail';
...@@ -65,6 +67,57 @@ describe('WindowSideBarCanvasPanel', () => { ...@@ -65,6 +67,57 @@ describe('WindowSideBarCanvasPanel', () => {
expect(wrapper.find(CanvasThumbnail).length).toBe(0); expect(wrapper.find(CanvasThumbnail).length).toBe(0);
}); });
it('renders elements for the TOC view', () => {
const wrapper = createWrapper({
structures: [{
id: 'top',
getLabel: () => [{ value: 'top' }],
getCanvasIds: () => [],
getRanges: () => [
{
id: '1', getLabel: () => [{ value: 'empty' }], getRanges: () => [], getCanvasIds: () => [],
},
{
id: '2',
getLabel: () => [{ value: 'one-with-ranges' }],
getRanges: () => [
{
id: '2.1', getLabel: () => [{ value: 'subrange' }], getRanges: () => [], getCanvasIds: () => [],
},
],
getCanvasIds: () => [],
},
{
id: '3',
getLabel: () => [{ value: 'one-with-canvases' }],
getRanges: () => [],
getCanvasIds: () => [
'http://iiif.io/api/presentation/2.0/example/fixtures/canvas/24/c1.json',
],
},
],
}],
});
wrapper.setState({ variant: 'toc' });
expect(wrapper.find(ExpansionPanel).length).toBe(5);
expect(wrapper
.find(ExpansionPanel)
.at(1)
.find(ExpansionPanelSummary)
.at(0)
.render()
.text()).toEqual('empty');
expect(wrapper.find(ExpansionPanel).at(2).find(List).find(ExpansionPanel).length).toEqual(1);
expect(wrapper
.find(ExpansionPanel).at(4).find(List)
.find(Typography)
.render()
.text()).toEqual('Test 19 Canvas: 1');
});
it('should set the correct labels', () => { it('should set the correct labels', () => {
const wrapper = createWrapper(); const wrapper = createWrapper();
......
...@@ -55,6 +55,7 @@ ...@@ -55,6 +55,7 @@
"thumbnailNavigation": "Miniaturansicht", "thumbnailNavigation": "Miniaturansicht",
"thumbnails": "Miniaturansicht", "thumbnails": "Miniaturansicht",
"thumbnailList": "Miniaturansicht", "thumbnailList": "Miniaturansicht",
"tocList": "Inhaltsverzeichnis",
"toggleWindowSideBar": "Seitenleiste umschalten", "toggleWindowSideBar": "Seitenleiste umschalten",
"tryAgain": "Wiederholen", "tryAgain": "Wiederholen",
"untitled": "[Unbenannt]", "untitled": "[Unbenannt]",
......
...@@ -59,6 +59,7 @@ ...@@ -59,6 +59,7 @@
"thumbnailNavigation": "Thumbnail carousel", "thumbnailNavigation": "Thumbnail carousel",
"thumbnails": "Thumbnails", "thumbnails": "Thumbnails",
"thumbnailList": "Thumbnail List", "thumbnailList": "Thumbnail List",
"tocList": "Table of Contents",
"toggleWindowSideBar": "Toggle window sidebar", "toggleWindowSideBar": "Toggle window sidebar",
"tryAgain": "Try again", "tryAgain": "Try again",
"untitled": "[Untitled]", "untitled": "[Untitled]",
......
...@@ -8,6 +8,9 @@ import FilledInput from '@material-ui/core/FilledInput'; ...@@ -8,6 +8,9 @@ import FilledInput from '@material-ui/core/FilledInput';
import MenuItem from '@material-ui/core/MenuItem'; import MenuItem from '@material-ui/core/MenuItem';
import FormControl from '@material-ui/core/FormControl'; import FormControl from '@material-ui/core/FormControl';
import Select from '@material-ui/core/Select'; import Select from '@material-ui/core/Select';
import ExpansionPanel from '@material-ui/core/ExpansionPanel';
import ExpansionPanelSummary from '@material-ui/core/ExpansionPanelSummary';
import ExpansionPanelDetails from '@material-ui/core/ExpansionPanelDetails';
import { CanvasThumbnail } from './CanvasThumbnail'; import { CanvasThumbnail } from './CanvasThumbnail';
import ManifestoCanvas from '../lib/ManifestoCanvas'; import ManifestoCanvas from '../lib/ManifestoCanvas';
import CompanionWindow from '../containers/CompanionWindow'; import CompanionWindow from '../containers/CompanionWindow';
...@@ -78,18 +81,118 @@ export class WindowSideBarCanvasPanel extends Component { ...@@ -78,18 +81,118 @@ export class WindowSideBarCanvasPanel extends Component {
); );
} }
/** */
renderToc(structures, defaultExpanded = false) {
const {
canvases, classes, setCanvas, windowId,
} = this.props;
return (
structures.map(canvasOrRange => (
<ExpansionPanel
defaultExpanded={defaultExpanded}
key={canvasOrRange.id}
elevation={0}
square
>
<ExpansionPanelSummary style={{ backgroundColor: '#eee' }}>
{canvasOrRange.getLabel().map(label => label.value)[0]}
</ExpansionPanelSummary>
<ExpansionPanelDetails style={{ flexDirection: 'column', paddingRight: 0, paddingLeft: 8 }}>
{
canvasOrRange.getRanges().length > 0
&& (
<List>
{
this.renderToc(canvasOrRange.getRanges())
}
</List>
)
}
<List>
{
canvasOrRange.getCanvasIds().map((canvasId) => {
const canvas = canvases.find(e => e.id === canvasId);
if (!canvas) return <></>;
const onClick = () => { setCanvas(windowId, canvas.index); }; // eslint-disable-line require-jsdoc, max-len
return (
<ListItem
key={canvas.id}
alignItems="flex-start"
onClick={onClick}
button
component="li"
disableGutters
>
<Typography
className={classNames(classes.label)}
variant="body2"
>
{canvas.getLabel().map(label => label.value)[0]}
</Typography>
</ListItem>
);
})
}
</List>
</ExpansionPanelDetails>
</ExpansionPanel>
))
);
}
/** */
renderList() {
const {
canvases, structures, setCanvas, windowId,
} = this.props;
const { variant } = this.state;
const canvasesIdAndLabel = getIdAndLabelOfCanvases(canvases);
switch (variant) {
case 'toc':
return this.renderToc(structures, true);
default:
return (
<List>
{
canvasesIdAndLabel.map((canvas, canvasIndex) => {
const onClick = () => { setCanvas(windowId, canvasIndex); }; // eslint-disable-line require-jsdoc, max-len
return (
<ListItem
key={canvas.id}
alignItems="flex-start"
onClick={onClick}
button
component="li"
>
{variant === 'compact' && this.renderCompact(canvas, canvases[canvasIndex])}
{variant === 'thumbnail' && this.renderThumbnail(canvas, canvases[canvasIndex])}
</ListItem>
);
})
}
</List>
);
}
}
/** /**
* render * render
*/ */
render() { render() {
const { const {
canvases, setCanvas, t, windowId, id, t, windowId, id, structures,
} = this.props; } = this.props;
const { variant } = this.state; const { variant } = this.state;
const canvasesIdAndLabel = getIdAndLabelOfCanvases(canvases);
return ( return (
<CompanionWindow <CompanionWindow
title={t('canvasIndex')} title={t('canvasIndex')}
...@@ -107,30 +210,12 @@ export class WindowSideBarCanvasPanel extends Component { ...@@ -107,30 +210,12 @@ export class WindowSideBarCanvasPanel extends Component {
> >
<MenuItem value="compact">{ t('compactList') }</MenuItem> <MenuItem value="compact">{ t('compactList') }</MenuItem>
<MenuItem value="thumbnail">{ t('thumbnailList') }</MenuItem> <MenuItem value="thumbnail">{ t('thumbnailList') }</MenuItem>
{ structures.length > 0 && <MenuItem value="toc">{ t('tocList') }</MenuItem> }
</Select> </Select>
</FormControl> </FormControl>
)} )}
> >
<List> { this.renderList() }
{
canvasesIdAndLabel.map((canvas, canvasIndex) => {
const onClick = () => { setCanvas(windowId, canvasIndex); }; // eslint-disable-line require-jsdoc, max-len
return (
<ListItem
key={canvas.id}
alignItems="flex-start"
onClick={onClick}
button
component="li"
>
{variant === 'compact' && this.renderCompact(canvas, canvases[canvasIndex])}
{variant === 'thumbnail' && this.renderThumbnail(canvas, canvases[canvasIndex])}
</ListItem>
);
})
}
</List>
</CompanionWindow> </CompanionWindow>
); );
} }
...@@ -138,6 +223,7 @@ export class WindowSideBarCanvasPanel extends Component { ...@@ -138,6 +223,7 @@ export class WindowSideBarCanvasPanel extends Component {
WindowSideBarCanvasPanel.propTypes = { WindowSideBarCanvasPanel.propTypes = {
canvases: PropTypes.array.isRequired, // eslint-disable-line react/forbid-prop-types canvases: PropTypes.array.isRequired, // eslint-disable-line react/forbid-prop-types
structures: PropTypes.array, // eslint-disable-line react/forbid-prop-types
classes: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types classes: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
config: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types config: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
setCanvas: PropTypes.func.isRequired, setCanvas: PropTypes.func.isRequired,
...@@ -145,3 +231,7 @@ WindowSideBarCanvasPanel.propTypes = { ...@@ -145,3 +231,7 @@ WindowSideBarCanvasPanel.propTypes = {
windowId: PropTypes.string.isRequired, windowId: PropTypes.string.isRequired,
id: PropTypes.string.isRequired, id: PropTypes.string.isRequired,
}; };
WindowSideBarCanvasPanel.defaultProps = {
structures: [],
};
...@@ -6,6 +6,7 @@ import * as actions from '../state/actions'; ...@@ -6,6 +6,7 @@ import * as actions from '../state/actions';
import { WindowSideBarCanvasPanel } from '../components/WindowSideBarCanvasPanel'; import { WindowSideBarCanvasPanel } from '../components/WindowSideBarCanvasPanel';
import { import {
getManifestCanvases, getManifestCanvases,
getManifestStructures,
getWindowManifest, getWindowManifest,
} from '../state/selectors'; } from '../state/selectors';
...@@ -15,10 +16,12 @@ import { ...@@ -15,10 +16,12 @@ import {
const mapStateToProps = (state, { windowId }) => { const mapStateToProps = (state, { windowId }) => {
const manifest = getWindowManifest(state, windowId); const manifest = getWindowManifest(state, windowId);
const canvases = getManifestCanvases(manifest); const canvases = getManifestCanvases(manifest);
const structures = getManifestStructures(manifest);
const { config } = state; const { config } = state;
return { return {
canvases, canvases,
config, config,
structures,
}; };
}; };
......
...@@ -70,6 +70,21 @@ export function getManifestCanvases(manifest) { ...@@ -70,6 +70,21 @@ export function getManifestCanvases(manifest) {
return manifest.manifestation.getSequences()[0].getCanvases(); return manifest.manifestation.getSequences()[0].getCanvases();
} }
/**
* Return the structures of a manifest or an empty Array
*/
export function getManifestStructures(manifest) {
if (!manifest.manifestation) {
return [];
}
if (!manifest.manifestation.getTopRanges) {
return [];
}
return manifest.manifestation.getTopRanges();
}
/** /**
* Return ids and labels of canvases * Return ids and labels of canvases
* @ param {Array} canvases * @ param {Array} canvases
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment