diff --git a/__tests__/integration/mirador/collections.html b/__tests__/integration/mirador/collections.html index 71056abebb40bdb553e5ec8e44de0b91f2f1d7ed..c41b9135a66663c75ae8414249d1495a5050f988 100644 --- a/__tests__/integration/mirador/collections.html +++ b/__tests__/integration/mirador/collections.html @@ -13,16 +13,18 @@ <script type="text/javascript"> var miradorInstance = Mirador.viewer({ id: 'mirador', - windows: [{ - manifestId: 'https://www.e-codices.unifr.ch/metadata/iiif/collection.json' - }], - // windows: [{ - // collectionPath: [ - // "https://www.e-codices.unifr.ch/metadata/iiif/collection.json", - // "https://www.e-codices.unifr.ch/metadata/iiif/collection/stabs.json" - // ], - // manifestId: "https://www.e-codices.unifr.ch/metadata/iiif/stabs-StAlban-DD1-1580/manifest.json" - // }], + windows: [ + { + collectionPath: [ + "https://www.e-codices.unifr.ch/metadata/iiif/collection.json", + "https://www.e-codices.unifr.ch/metadata/iiif/collection/stabs.json" + ], + manifestId: "https://www.e-codices.unifr.ch/metadata/iiif/stabs-StAlban-DD1-1580/manifest.json" + }, + { + manifestId: 'https://www.e-codices.unifr.ch/metadata/iiif/collection.json' + } + ], catalog: [ { manifestId: "https://www.e-codices.unifr.ch/metadata/iiif/collection.json" }, ] diff --git a/__tests__/src/components/PrimaryWindow.test.js b/__tests__/src/components/PrimaryWindow.test.js index da8de5fbb361e89e08f79eab302d69aa9533b5aa..5cdcccfe63b6c8f4ec3125a91dc6c9ce13a0b619 100644 --- a/__tests__/src/components/PrimaryWindow.test.js +++ b/__tests__/src/components/PrimaryWindow.test.js @@ -4,6 +4,7 @@ import { PrimaryWindow } from '../../../src/components/PrimaryWindow'; import WindowSideBar from '../../../src/containers/WindowSideBar'; import WindowViewer from '../../../src/containers/WindowViewer'; import GalleryView from '../../../src/containers/GalleryView'; +import CollectionDialog from '../../../src/containers/CollectionDialog'; /** create wrapper */ function createWrapper(props) { @@ -37,4 +38,10 @@ describe('PrimaryWindow', () => { const wrapper = createWrapper({ isFetching: false, view: 'gallery', windowId: 'window-2' }); expect(wrapper.find(GalleryView)).toHaveLength(1); }); + it('should render <CollectionDialog> and <SelectCollection> if manifest is collection and isCollectionDialogVisible', () => { + const wrapper = createWrapper({ isCollection: true, isCollectionDialogVisible: true }); + const lazyComponent = wrapper.find('lazy'); + expect(lazyComponent.type().displayName).toBe('SelectCollection'); + expect(wrapper.find(CollectionDialog)).toHaveLength(1); + }); }); diff --git a/src/components/CollectionDialog.js b/src/components/CollectionDialog.js index 59730884c4e6500cf80b40a554067096a217c909..9930997f3c7daa509f9d0093f5df9ac18abc9c61 100644 --- a/src/components/CollectionDialog.js +++ b/src/components/CollectionDialog.js @@ -102,12 +102,15 @@ export class CollectionDialog extends Component { /** */ placeholder() { - const { classes, hideCollectionDialog } = this.props; + const { classes, containerId, hideCollectionDialog, windowId } = this.props; return ( <Dialog + className={classes.dialog} onClose={hideCollectionDialog} open + container={document.querySelector(`#${containerId} #${windowId}`)} + BackdropProps={{ classes: classes.dialog }} > <DialogTitle id="select-collection" disableTypography> <Skeleton className={classes.placeholder} variant="text" /> @@ -125,12 +128,14 @@ export class CollectionDialog extends Component { const { classes, collection, + containerId, error, hideCollectionDialog, isMultipart, manifest, ready, t, + windowId, } = this.props; const { filter } = this.state; @@ -152,7 +157,10 @@ export class CollectionDialog extends Component { return ( <Dialog + className={classes.dialog} onClose={hideCollectionDialog} + container={document.querySelector(`#${containerId} #${windowId}`)} + BackdropProps={{ classes: { root: classes.dialog }}} open > <DialogTitle id="select-collection" disableTypography> @@ -260,6 +268,7 @@ CollectionDialog.propTypes = { CollectionDialog.defaultProps = { collection: null, collectionPath: [], + containerId: null, error: null, isMultipart: false, ready: false, diff --git a/src/components/PrimaryWindow.js b/src/components/PrimaryWindow.js index e96811e9ba45de018221ad08c5c50dc62ad72325..d440b9759d93acdc7b921c4393b866f4209469b5 100644 --- a/src/components/PrimaryWindow.js +++ b/src/components/PrimaryWindow.js @@ -1,4 +1,4 @@ -import React, { Component } from 'react'; +import React, { Component, lazy } from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; import WindowSideBar from '../containers/WindowSideBar'; @@ -7,6 +7,9 @@ import GalleryView from '../containers/GalleryView'; import CompanionArea from '../containers/CompanionArea'; import ns from '../config/css-ns'; +const SelectCollection = lazy(() => import('../containers/SelectCollection')); +SelectCollection.displayName = 'SelectCollection'; + /** * WindowMiddleContent - component that renders the "middle" area of the * Mirador Window @@ -18,7 +21,16 @@ export class PrimaryWindow extends Component { * @return {(String|null)} */ renderViewer() { - const { isFetching, view, windowId } = this.props; + const { + isCollection, isFetching, view, windowId, + } = this.props; + if (isCollection) { + return ( + <SelectCollection + windowId={windowId} + /> + ); + } if (isFetching === false) { if (view === 'gallery') { return ( @@ -53,12 +65,14 @@ export class PrimaryWindow extends Component { PrimaryWindow.propTypes = { classes: PropTypes.objectOf(PropTypes.string).isRequired, + isCollection: PropTypes.bool, isFetching: PropTypes.bool, view: PropTypes.string, windowId: PropTypes.string.isRequired, }; PrimaryWindow.defaultProps = { + isCollection: false, isFetching: false, view: undefined, }; diff --git a/src/components/SelectCollection.js b/src/components/SelectCollection.js new file mode 100644 index 0000000000000000000000000000000000000000..decfdf6deabd97cf10e3238e22d0e31294434458 --- /dev/null +++ b/src/components/SelectCollection.js @@ -0,0 +1,67 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import Button from '@material-ui/core/Button'; +import Grid from '@material-ui/core/Grid'; +import Typography from '@material-ui/core/Typography'; +import ListSharpIcon from '@material-ui/icons/ListSharp'; + +/** + * + */ +export class SelectCollection extends Component { + /** */ + constructor(props) { + super(props); + + this.openCollectionDialog = this.openCollectionDialog.bind(this); + } + + /** */ + openCollectionDialog() { + const { + collectionPath, manifestId, showCollectionDialog, windowId, + } = this.props; + showCollectionDialog(manifestId, collectionPath.slice(0, -1), windowId); + } + + /** */ + render() { + const { + t, + } = this.props; + return ( + <Grid container justify="center" alignItems="center"> + <Grid container direction="column" alignItems="center"> + <Typography variant="h4" paragraph> + <em> + {t('noItemSelected')} + </em> + </Typography> + <Button + color="primary" + variant="contained" + onClick={this.openCollectionDialog} + startIcon={<ListSharpIcon />} + > + {t('showCollection')} + </Button> + </Grid> + </Grid> + ); + } +} + +SelectCollection.propTypes = { + collectionPath: PropTypes.arrayOf(PropTypes.string), + manifestId: PropTypes.string, + showCollectionDialog: PropTypes.func.isRequired, + t: PropTypes.func, + windowId: PropTypes.string, +}; + +SelectCollection.defaultProps = { + collectionPath: [], + manifestId: null, + t: () => {}, + windowId: null, +}; diff --git a/src/containers/CollectionDialog.js b/src/containers/CollectionDialog.js index 8c1f687ed52e57b50e65a8223a5da446a47d3ebb..325640145683690aee9042aa2fbcf5d84ed56eeb 100644 --- a/src/containers/CollectionDialog.js +++ b/src/containers/CollectionDialog.js @@ -4,7 +4,9 @@ import { withStyles } from '@material-ui/core'; import { withTranslation } from 'react-i18next'; import { withPlugins } from '../extend/withPlugins'; import * as actions from '../state/actions'; -import { getManifest, getManifestoInstance, getSequenceBehaviors } from '../state/selectors'; +import { + getContainerId, getManifest, getManifestoInstance, getSequenceBehaviors, +} from '../state/selectors'; import { CollectionDialog } from '../components/CollectionDialog'; /** @@ -35,6 +37,7 @@ const mapStateToProps = (state) => { return { collection: collection && getManifestoInstance(state, { manifestId: collection.id }), collectionPath, + containerId: getContainerId(state), error: manifest && manifest.error, isMultipart: getSequenceBehaviors(state, { manifestId }).includes('multi-part'), manifest: manifest && getManifestoInstance(state, { manifestId }), @@ -57,6 +60,9 @@ const styles = theme => ({ dark: { color: '#000000', }, + dialog: { + position: 'absolute !important', + }, dialogContent: { padding: 0, }, diff --git a/src/containers/PrimaryWindow.js b/src/containers/PrimaryWindow.js index 4c90a12946893d6dfc20936ae1754a41bf34c452..50332d7c899f5dd8c5e877d2c3142806e5c203c5 100644 --- a/src/containers/PrimaryWindow.js +++ b/src/containers/PrimaryWindow.js @@ -1,8 +1,18 @@ import { compose } from 'redux'; +import { connect } from 'react-redux'; import { withStyles } from '@material-ui/core/styles'; import { withPlugins } from '../extend/withPlugins'; +import { getManifestoInstance } from '../state/selectors'; import { PrimaryWindow } from '../components/PrimaryWindow'; +/** */ +const mapStateToProps = (state, { windowId }) => { + const manifestoInstance = getManifestoInstance(state, { windowId }); + return { + isCollection: manifestoInstance && manifestoInstance.isCollection(), + }; +}; + const styles = { primaryWindow: { display: 'flex', @@ -13,6 +23,7 @@ const styles = { const enhance = compose( withStyles(styles), + connect(mapStateToProps), withPlugins('PrimaryWindow'), ); diff --git a/src/containers/SelectCollection.js b/src/containers/SelectCollection.js new file mode 100644 index 0000000000000000000000000000000000000000..446c32711f233e68c9ca4fe904e643c4e71d0ab2 --- /dev/null +++ b/src/containers/SelectCollection.js @@ -0,0 +1,36 @@ +import { compose } from 'redux'; +import { connect } from 'react-redux'; +import { withTranslation } from 'react-i18next'; +import { withStyles } from '@material-ui/core/styles'; +import * as actions from '../state/actions'; +import { withPlugins } from '../extend/withPlugins'; +import { + getWindow, +} from '../state/selectors'; +import { SelectCollection } from '../components/SelectCollection'; + +/** */ +const mapStateToProps = (state, { windowId }) => { + const { collectionPath, manifestId } = (getWindow(state, { windowId }) || {}); + + return { + collectionPath, + manifestId, + }; +}; + +const mapDispatchToProps = { + showCollectionDialog: actions.showCollectionDialog, +}; +/** */ +const styles = (theme) => ({ +}); + +const enhance = compose( + withTranslation(), + withStyles(styles), + connect(mapStateToProps, mapDispatchToProps), + withPlugins('SelectCollection'), +); + +export default enhance(SelectCollection); diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index 8c0756f50b71fda54e644df3c939ecf5356dd000..c6c0ef9d2d0adf711fa6f234d95b53e6205fe013 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -90,6 +90,7 @@ "moveCompanionWindowToBottom": "Move to bottom", "moveCompanionWindowToRight": "Move to right", "nextCanvas": "Next item", + "noItemSelected": "No item selected", "numItems": "{{number}} items", "off": "Off", "openCompanionWindow_annotations": "Annotations", diff --git a/src/state/actions/workspace.js b/src/state/actions/workspace.js index 47740062cf20d550aba85ebaee17eac25daf73b0..29c52e0f1f36434d121bd983f8be8f2c660b771e 100644 --- a/src/state/actions/workspace.js +++ b/src/state/actions/workspace.js @@ -95,7 +95,6 @@ export function toggleDraggingEnabled() { /** */ export function showCollectionDialog(manifestId, collectionPath = [], windowId = null) { - console.log(manifestId, collectionPath); return { collectionPath, manifestId,