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';
import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
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 { WindowSideBarCanvasPanel } from '../../../src/components/WindowSideBarCanvasPanel';
import { CanvasThumbnail } from '../../../src/components/CanvasThumbnail';
......@@ -65,6 +67,57 @@ describe('WindowSideBarCanvasPanel', () => {
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', () => {
const wrapper = createWrapper();
......
......@@ -55,6 +55,7 @@
"thumbnailNavigation": "Miniaturansicht",
"thumbnails": "Miniaturansicht",
"thumbnailList": "Miniaturansicht",
"tocList": "Inhaltsverzeichnis",
"toggleWindowSideBar": "Seitenleiste umschalten",
"tryAgain": "Wiederholen",
"untitled": "[Unbenannt]",
......
......@@ -59,6 +59,7 @@
"thumbnailNavigation": "Thumbnail carousel",
"thumbnails": "Thumbnails",
"thumbnailList": "Thumbnail List",
"tocList": "Table of Contents",
"toggleWindowSideBar": "Toggle window sidebar",
"tryAgain": "Try again",
"untitled": "[Untitled]",
......
......@@ -8,6 +8,9 @@ import FilledInput from '@material-ui/core/FilledInput';
import MenuItem from '@material-ui/core/MenuItem';
import FormControl from '@material-ui/core/FormControl';
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 ManifestoCanvas from '../lib/ManifestoCanvas';
import CompanionWindow from '../containers/CompanionWindow';
......@@ -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() {
const {
canvases, setCanvas, t, windowId, id,
t, windowId, id, structures,
} = this.props;
const { variant } = this.state;
const canvasesIdAndLabel = getIdAndLabelOfCanvases(canvases);
return (
<CompanionWindow
title={t('canvasIndex')}
......@@ -107,30 +210,12 @@ export class WindowSideBarCanvasPanel extends Component {
>
<MenuItem value="compact">{ t('compactList') }</MenuItem>
<MenuItem value="thumbnail">{ t('thumbnailList') }</MenuItem>
{ structures.length > 0 && <MenuItem value="toc">{ t('tocList') }</MenuItem> }
</Select>
</FormControl>
)}
>
<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>
{ this.renderList() }
</CompanionWindow>
);
}
......@@ -138,6 +223,7 @@ export class WindowSideBarCanvasPanel extends Component {
WindowSideBarCanvasPanel.propTypes = {
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
config: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
setCanvas: PropTypes.func.isRequired,
......@@ -145,3 +231,7 @@ WindowSideBarCanvasPanel.propTypes = {
windowId: PropTypes.string.isRequired,
id: PropTypes.string.isRequired,
};
WindowSideBarCanvasPanel.defaultProps = {
structures: [],
};
......@@ -6,6 +6,7 @@ import * as actions from '../state/actions';
import { WindowSideBarCanvasPanel } from '../components/WindowSideBarCanvasPanel';
import {
getManifestCanvases,
getManifestStructures,
getWindowManifest,
} from '../state/selectors';
......@@ -15,10 +16,12 @@ import {
const mapStateToProps = (state, { windowId }) => {
const manifest = getWindowManifest(state, windowId);
const canvases = getManifestCanvases(manifest);
const structures = getManifestStructures(manifest);
const { config } = state;
return {
canvases,
config,
structures,
};
};
......
......@@ -70,6 +70,21 @@ export function getManifestCanvases(manifest) {
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
* @ param {Array} canvases
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment