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

Merge pull request #1850 from ProjectMirador/1790-bookview-selections

Setup the ability to select single vs bookview
parents 62f34d75 0909054b
Branches
Tags
No related merge requests found
...@@ -20,6 +20,7 @@ describe('window actions', () => { ...@@ -20,6 +20,7 @@ describe('window actions', () => {
thumbnailNavigationPosition: 'bottom', thumbnailNavigationPosition: 'bottom',
xywh: [0, 0, 400, 400], xywh: [0, 0, 400, 400],
rotation: null, rotation: null,
view: 'single',
}, },
}; };
expect(actions.addWindow(options)).toEqual(expectedAction); expect(actions.addWindow(options)).toEqual(expectedAction);
...@@ -59,6 +60,18 @@ describe('window actions', () => { ...@@ -59,6 +60,18 @@ describe('window actions', () => {
}); });
}); });
describe('setWindowViewType', () => {
it('returns the appropriate action type', () => {
const id = 'abc123';
const expectedAction = {
type: ActionTypes.SET_WINDOW_VIEW_TYPE,
windowId: id,
viewType: 'book',
};
expect(actions.setWindowViewType(id, 'book')).toEqual(expectedAction);
});
});
describe('toggleWindowSideBarPanel', () => { describe('toggleWindowSideBarPanel', () => {
it('returns the appropriate action type', () => { it('returns the appropriate action type', () => {
const windowId = 'abc123'; const windowId = 'abc123';
......
...@@ -4,6 +4,7 @@ import ListItem from '@material-ui/core/ListItem'; ...@@ -4,6 +4,7 @@ import ListItem from '@material-ui/core/ListItem';
import Menu from '@material-ui/core/Menu'; import Menu from '@material-ui/core/Menu';
import Divider from '@material-ui/core/Divider'; import Divider from '@material-ui/core/Divider';
import WindowThumbnailSettings from '../../../src/containers/WindowThumbnailSettings'; import WindowThumbnailSettings from '../../../src/containers/WindowThumbnailSettings';
import WindowViewSettings from '../../../src/containers/WindowViewSettings';
import WindowTopMenu from '../../../src/components/WindowTopMenu'; import WindowTopMenu from '../../../src/components/WindowTopMenu';
/** create wrapper */ /** create wrapper */
...@@ -22,9 +23,10 @@ describe('WindowTopMenu', () => { ...@@ -22,9 +23,10 @@ describe('WindowTopMenu', () => {
it('renders all needed elements', () => { it('renders all needed elements', () => {
const wrapper = createWrapper(); const wrapper = createWrapper();
expect(wrapper.find(Menu).length).toBe(1); expect(wrapper.find(Menu).length).toBe(1);
expect(wrapper.find(ListItem).length).toBe(1); expect(wrapper.find(ListItem).length).toBe(2);
expect(wrapper.find(WindowThumbnailSettings).length).toBe(1); expect(wrapper.find(WindowThumbnailSettings).length).toBe(1);
expect(wrapper.find(Divider).length).toBe(1); expect(wrapper.find(WindowViewSettings).length).toBe(1);
expect(wrapper.find(Divider).length).toBe(2);
}); });
it('passes windowId to <WindowThumbnailSettings/>', () => { it('passes windowId to <WindowThumbnailSettings/>', () => {
......
import React from 'react';
import { shallow } from 'enzyme';
import FormControlLabel from '@material-ui/core/FormControlLabel';
import RadioGroup from '@material-ui/core/RadioGroup';
import Typography from '@material-ui/core/Typography';
import WindowViewSettings from '../../../src/components/WindowViewSettings';
/** create wrapper */
function createWrapper(props) {
return shallow(
<WindowViewSettings
windowId="xyz"
setWindowViewType={() => {}}
windowViewType="single"
{...props}
/>,
);
}
describe('WindowViewSettings', () => {
it('renders all elements correctly', () => {
const wrapper = createWrapper();
expect(wrapper.find(Typography).length).toBe(1);
expect(wrapper.find(RadioGroup).length).toBe(1);
const labels = wrapper.find(FormControlLabel);
expect(labels.length).toBe(2);
expect(labels.at(0).props().value).toBe('single');
expect(labels.at(1).props().value).toBe('book');
});
it('should set the correct label active', () => {
let wrapper = createWrapper({ windowViewType: 'single' });
expect(wrapper.find(RadioGroup).props().value).toBe('single');
wrapper = createWrapper({ windowViewType: 'book' });
expect(wrapper.find(RadioGroup).props().value).toBe('book');
});
it('updates state when the view config selection changes', () => {
const setWindowViewType = jest.fn();
const wrapper = createWrapper({ setWindowViewType });
wrapper.find(RadioGroup).first().simulate('change', { target: { value: 'book' } });
expect(setWindowViewType).toHaveBeenCalledWith('xyz', 'book');
wrapper.find(RadioGroup).first().simulate('change', { target: { value: 'single' } });
expect(setWindowViewType).toHaveBeenCalledWith('xyz', 'single');
});
});
...@@ -65,6 +65,24 @@ describe('windows reducer', () => { ...@@ -65,6 +65,24 @@ describe('windows reducer', () => {
expect(reducer(before, action)).toEqual(after); expect(reducer(before, action)).toEqual(after);
}); });
it('should handle SET_WINDOW_VIEW_TYPE by changing the view attribute', () => {
const action = {
type: ActionTypes.SET_WINDOW_VIEW_TYPE,
windowId: 'abc123',
viewType: 'book',
};
const before = {
abc123: { view: 'single' },
abc321: { view: 'book' },
};
const after = {
abc123: { view: 'book' },
abc321: { view: 'book' },
};
expect(reducer(before, action)).toEqual(after);
});
describe('TOGGLE_WINDOW_SIDE_BAR_PANEL', () => { describe('TOGGLE_WINDOW_SIDE_BAR_PANEL', () => {
it('sets the sideBarPanel value to the given value when it was changed', () => { it('sets the sideBarPanel value to the given value when it was changed', () => {
const action = { const action = {
......
...@@ -6,6 +6,7 @@ import { ...@@ -6,6 +6,7 @@ import {
getManifestCanvases, getManifestCanvases,
getThumbnailNavigationPosition, getThumbnailNavigationPosition,
getManifestTitle, getManifestTitle,
getWindowViewType,
} from '../../../src/state/selectors'; } from '../../../src/state/selectors';
...@@ -114,3 +115,27 @@ describe('getManifestTitle', () => { ...@@ -114,3 +115,27 @@ describe('getManifestTitle', () => {
expect(received).toBeUndefined(); expect(received).toBeUndefined();
}); });
}); });
describe('getWindowViewType', () => {
const state = {
windows: {
a: { id: 'a', view: 'single' },
b: { id: 'b' },
},
};
it('should return view type if window exists', () => {
const received = getWindowViewType(state, 'a');
expect(received).toBe('single');
});
it('should return undefined if view type does not exist in window', () => {
const received = getWindowViewType(state, 'b');
expect(received).toBeUndefined();
});
it('should return undefined if window does not exists', () => {
const received = getWindowViewType(state, 'c');
expect(received).toBeUndefined();
});
});
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
"translation": { "translation": {
"aboutThisItem": "About this item", "aboutThisItem": "About this item",
"add": "Add", "add": "Add",
"book": "Book",
"bottom": "Bottom", "bottom": "Bottom",
"closeInfoCompanionWindow": "Close information companion window", "closeInfoCompanionWindow": "Close information companion window",
"closeMenu": "Close Menu", "closeMenu": "Close Menu",
...@@ -19,11 +20,13 @@ ...@@ -19,11 +20,13 @@
"openWindows": "Open windows", "openWindows": "Open windows",
"position": "Position", "position": "Position",
"right": "Right", "right": "Right",
"single": "Single",
"settings": "Settings", "settings": "Settings",
"theme": "Theme", "theme": "Theme",
"thumbnails": "Thumbnails", "thumbnails": "Thumbnails",
"toggleWindowSideBar": "Toggle window sidebar", "toggleWindowSideBar": "Toggle window sidebar",
"untitled": "[Untitled]", "untitled": "[Untitled]",
"view": "View",
"zoomIn": "Zoom in", "zoomIn": "Zoom in",
"zoomOut": "Zoom out", "zoomOut": "Zoom out",
"zoomReset": "Reset zoom" "zoomReset": "Reset zoom"
......
...@@ -4,6 +4,7 @@ import Menu from '@material-ui/core/Menu'; ...@@ -4,6 +4,7 @@ import Menu from '@material-ui/core/Menu';
import Divider from '@material-ui/core/Divider'; import Divider from '@material-ui/core/Divider';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import WindowThumbnailSettings from '../containers/WindowThumbnailSettings'; import WindowThumbnailSettings from '../containers/WindowThumbnailSettings';
import WindowViewSettings from '../containers/WindowViewSettings';
/** /**
*/ */
...@@ -19,6 +20,10 @@ class WindowTopMenu extends Component { ...@@ -19,6 +20,10 @@ class WindowTopMenu extends Component {
return ( return (
<> <>
<Menu id={`window-menu_${windowId}`} anchorEl={anchorEl} open={Boolean(anchorEl)} onClose={handleClose}> <Menu id={`window-menu_${windowId}`} anchorEl={anchorEl} open={Boolean(anchorEl)} onClose={handleClose}>
<ListItem>
<WindowViewSettings windowId={windowId} />
</ListItem>
<Divider />
<ListItem> <ListItem>
<WindowThumbnailSettings windowId={windowId} /> <WindowThumbnailSettings windowId={windowId} />
</ListItem> </ListItem>
......
import React, { Component } from 'react';
import FormControlLabel from '@material-ui/core/FormControlLabel';
import Radio from '@material-ui/core/Radio';
import RadioGroup from '@material-ui/core/RadioGroup';
import Typography from '@material-ui/core/Typography';
import PhotoIcon from '@material-ui/icons/Photo';
import ViewAgendaIcon from '@material-ui/icons/ViewAgenda';
import PropTypes from 'prop-types';
/**
*
*/
export default class WindowViewSettings extends Component {
/**
* constructor -
*/
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
/**
* @private
*/
handleChange(event) {
const { windowId, setWindowViewType } = this.props;
setWindowViewType(windowId, event.target.value);
}
/**
* render
*
* @return {type} description
*/
render() {
const { windowViewType, t } = this.props;
return (
<>
<Typography>{t('view')}</Typography>
<RadioGroup aria-label={t('position')} name="position" value={windowViewType} onChange={this.handleChange} row>
<FormControlLabel
value="single"
control={<Radio color="primary" icon={<PhotoIcon />} checkedIcon={<PhotoIcon />} />}
label={t('single')}
labelPlacement="bottom"
/>
<FormControlLabel
value="book"
control={<Radio color="primary" icon={<ViewAgendaIconRotated />} checkedIcon={<ViewAgendaIconRotated />} />}
label={t('book')}
labelPlacement="bottom"
/>
</RadioGroup>
</>
);
}
}
/**
* @private
*/
function ViewAgendaIconRotated(props) {
return (
<ViewAgendaIcon style={{ transform: 'rotate(-90deg)' }} />
);
}
WindowViewSettings.propTypes = {
windowId: PropTypes.string.isRequired,
setWindowViewType: PropTypes.func.isRequired,
windowViewType: PropTypes.string.isRequired,
t: PropTypes.func,
};
WindowViewSettings.defaultProps = {
t: key => key,
};
import { compose } from 'redux';
import { connect } from 'react-redux';
import { withNamespaces } from 'react-i18next';
import miradorWithPlugins from '../lib/miradorWithPlugins';
import * as actions from '../state/actions';
import { getWindowViewType } from '../state/selectors';
import WindowViewSettings from '../components/WindowViewSettings';
/**
* mapDispatchToProps - used to hook up connect to action creators
* @memberof ManifestListItem
* @private
*/
const mapDispatchToProps = { setWindowViewType: actions.setWindowViewType };
/**
* mapStateToProps - to hook up connect
* @memberof WindowViewer
* @private
*/
const mapStateToProps = (state, props) => (
{
windowViewType: getWindowViewType(state, props.windowId),
}
);
const enhance = compose(
connect(mapStateToProps, mapDispatchToProps),
withNamespaces(),
miradorWithPlugins,
// further HOC go here
);
export default enhance(WindowViewSettings);
...@@ -13,6 +13,7 @@ const ActionTypes = { ...@@ -13,6 +13,7 @@ const ActionTypes = {
RECEIVE_MANIFEST_FAILURE: 'RECEIVE_MANIFEST_FAILURE', RECEIVE_MANIFEST_FAILURE: 'RECEIVE_MANIFEST_FAILURE',
SET_CONFIG: 'SET_CONFIG', SET_CONFIG: 'SET_CONFIG',
SET_WINDOW_THUMBNAIL_POSITION: 'SET_WINDOW_THUMBNAIL_POSITION', SET_WINDOW_THUMBNAIL_POSITION: 'SET_WINDOW_THUMBNAIL_POSITION',
SET_WINDOW_VIEW_TYPE: 'SET_WINDOW_VIEW_TYPE',
TOGGLE_WINDOW_SIDE_BAR: 'TOGGLE_WINDOW_SIDE_BAR', TOGGLE_WINDOW_SIDE_BAR: 'TOGGLE_WINDOW_SIDE_BAR',
TOGGLE_WINDOW_SIDE_BAR_PANEL: 'TOGGLE_WINDOW_SIDE_BAR_PANEL', TOGGLE_WINDOW_SIDE_BAR_PANEL: 'TOGGLE_WINDOW_SIDE_BAR_PANEL',
TOGGLE_ZOOM_CONTROLS: 'TOGGLE_ZOOM_CONTROLS', TOGGLE_ZOOM_CONTROLS: 'TOGGLE_ZOOM_CONTROLS',
......
...@@ -27,6 +27,7 @@ export function addWindow(options) { ...@@ -27,6 +27,7 @@ export function addWindow(options) {
thumbnailNavigationPosition: 'bottom', // bottom by default in settings.js thumbnailNavigationPosition: 'bottom', // bottom by default in settings.js
xywh: [0, 0, 400, 400], xywh: [0, 0, 400, 400],
rotation: null, rotation: null,
view: 'single',
}; };
return { type: ActionTypes.ADD_WINDOW, window: { ...defaultOptions, ...options } }; return { type: ActionTypes.ADD_WINDOW, window: { ...defaultOptions, ...options } };
} }
...@@ -72,3 +73,14 @@ export function toggleWindowSideBarPanel(windowId, panelType) { ...@@ -72,3 +73,14 @@ export function toggleWindowSideBarPanel(windowId, panelType) {
export function setWindowThumbnailPosition(windowId, position) { export function setWindowThumbnailPosition(windowId, position) {
return { type: ActionTypes.SET_WINDOW_THUMBNAIL_POSITION, windowId, position }; return { type: ActionTypes.SET_WINDOW_THUMBNAIL_POSITION, windowId, position };
} }
/**
* setWindowViewType - action creator
*
* @param {String} windowId
* @param {String} viewType
* @memberof ActionCreators
*/
export function setWindowViewType(windowId, viewType) {
return { type: ActionTypes.SET_WINDOW_VIEW_TYPE, windowId, viewType };
}
...@@ -22,7 +22,14 @@ const windowsReducer = (state = {}, action) => { ...@@ -22,7 +22,14 @@ const windowsReducer = (state = {}, action) => {
sideBarOpen: !state[action.windowId].sideBarOpen, sideBarOpen: !state[action.windowId].sideBarOpen,
}, },
}; };
case ActionTypes.SET_WINDOW_VIEW_TYPE:
return {
...state,
[action.windowId]: {
...state[action.windowId],
view: action.viewType,
},
};
case ActionTypes.SET_WINDOW_THUMBNAIL_POSITION: case ActionTypes.SET_WINDOW_THUMBNAIL_POSITION:
return { return {
...state, ...state,
......
...@@ -54,3 +54,12 @@ export function getManifestTitle(manifest) { ...@@ -54,3 +54,12 @@ export function getManifestTitle(manifest) {
&& manifest.manifestation && manifest.manifestation
&& manifest.manifestation.getLabel().map(label => label.value)[0]; && manifest.manifestation.getLabel().map(label => label.value)[0];
} }
/** Return type of view in a certain window.
* @param {object} state
* @param {String} windowId
* @param {String}
*/
export function getWindowViewType(state, windowId) {
return state.windows[windowId] && state.windows[windowId].view;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment