diff --git a/src/components/AnnotationManifestsAccordion.js b/src/components/AnnotationManifestsAccordion.js index 749330b99e8777f0c74b35af0653534569c4f834..62766ec1cbc49628c984e486bfa2f9ace13b737a 100644 --- a/src/components/AnnotationManifestsAccordion.js +++ b/src/components/AnnotationManifestsAccordion.js @@ -5,11 +5,7 @@ import ExpandMoreIcon from '@material-ui/icons/ExpandMoreSharp'; import Typography from '@material-ui/core/Typography'; import AccordionDetails from '@material-ui/core/AccordionDetails'; import PropTypes from 'prop-types'; -import { - Card, CardActionArea, CardActions, CardContent, CardMedia, Fab, -} from '@material-ui/core'; -import Button from '@material-ui/core/Button'; -import Tooltip from '@material-ui/core/Tooltip'; +import AnnotationManifestsItem from '../containers/AnnotationManifestsItem'; /** * AnnotationManifestsAccordion @@ -20,9 +16,9 @@ export class AnnotationManifestsAccordion extends Component { */ constructor(props) { super(props); - this.handleOpenManifestSideToSide = this.handleOpenManifestSideToSide.bind(this); this.handleOpenAccordion = this.handleOpenAccordion.bind(this); + /** Search if the annotation is a manifest. URL must be resolvable for the annotation. So the manifest url is added at the end of the id */ function searchManifestInID(id) { const match = id.match( @@ -34,6 +30,7 @@ export class AnnotationManifestsAccordion extends Component { const { annotation } = this.props; + annotation.manifestsOpen = false; annotation.manifests = searchManifestInID(annotation.id); if (annotation.manifests) { annotation.manifests = annotation.manifests.map(id => ({ id })); @@ -44,38 +41,13 @@ export class AnnotationManifestsAccordion extends Component { this.state = { annotation }; } - - /** */ - handleOpenManifestSideToSide(e, manifestId) { - const { addResource, addWindow } = this.props; - addResource(manifestId); - addWindow({ manifestId }); - } - /** */ // eslint-disable-next-line class-methods-use-this,require-jsdoc handleOpenAccordion(e) { - const { annotation } = this.state; - /** */ - async function load(manifests) { - return Promise.all(manifests.map((manifest) => fetch(manifest.id) - .then((response) => response.json()) - .then((data) => { - if (data.type === 'Manifest') { - return data; - } - return null; - }))); - } - - load(annotation.manifests) - .then((values) => { - if (values) { - annotation.manifests = values; - this.setState({ annotation }); - } - }); + let { annotation } = this.state; + annotation.manifestsOpen = true; e.stopPropagation(); + this.state = { annotation }; } /** */ @@ -84,8 +56,6 @@ export class AnnotationManifestsAccordion extends Component { classes, t, i18n, } = this.props; - const language = i18n.language; - const { annotation } = this.state; if (annotation.manifests === null || annotation.manifests.length === 0) { @@ -101,34 +71,20 @@ export class AnnotationManifestsAccordion extends Component { > <Typography className={classes.heading}>{t('manifestFound')}</Typography> </AccordionSummary> - <AccordionDetails className={classes.manifestContainer}> - {annotation.manifests.map(manifest => ( - <Typography > - <Card className={classes.root}> - <CardActionArea> - <CardContent> - <Typography> - { manifest.label ? manifest.label[language] : manifest.id } - </Typography> - </CardContent> - </CardActionArea> - <CardActions> - <Tooltip title={t('openManifestInOtherWindow', { manifest: manifest.id })}> - <Button - size="small" - color="primary" - onClick={(e) => { - this.handleOpenManifestSideToSide(e, manifest.id); - }} - > - {t('open')} - </Button> - </Tooltip> - </CardActions> - </Card> - </Typography> - ))} - </AccordionDetails> + { + annotation.manifestsOpen && ( + <AccordionDetails className={classes.manifestContainer}> + {annotation.manifests.map(manifest => ( + <AnnotationManifestsItem + manifestId={manifest.id} + language={i18n.language} + key={manifest} + t={t} + /> + ))} + </AccordionDetails> + ) + } </Accordion> </div> ); @@ -136,16 +92,17 @@ export class AnnotationManifestsAccordion extends Component { } AnnotationManifestsAccordion.propsTypes = { - addResource: PropTypes.func.isRequired, - addWindow: PropTypes.func.isRequired, + annotation: PropTypes.shape( { content: PropTypes.string, id: PropTypes.string, manifests: PropTypes.arrayOf(PropTypes.string), + manifestsOpen: PropTypes.boolean, }, ), classes: PropTypes.objectOf(PropTypes.string), + fetchManifest: PropTypes.func.isRequired, t: PropTypes.func.isRequired, }; diff --git a/src/components/AnnotationManifestsItem.js b/src/components/AnnotationManifestsItem.js new file mode 100644 index 0000000000000000000000000000000000000000..657a5c84255d26426cdaf67f5360b3c53ca00fc2 --- /dev/null +++ b/src/components/AnnotationManifestsItem.js @@ -0,0 +1,131 @@ +import { Component } from 'react'; +import Typography from '@material-ui/core/Typography'; +import PropTypes from 'prop-types'; +import { + Card, CardActionArea, CardActions, CardContent, CardMedia, Fab, +} from '@material-ui/core'; +import Button from '@material-ui/core/Button'; +import Tooltip from '@material-ui/core/Tooltip'; + +/** + * AnnotationManifestsItem + */ +export class AnnotationManifestsItem extends Component { + /** + * constructor + */ + constructor(props) { + super(props); + this.handleOpenManifestSideToSide = this.handleOpenManifestSideToSide.bind(this); + } + + /** */ + componentDidMount() { + const { + fetchManifest, manifestId, ready, isFetching, error, provider, + } = this.props; + + if (!ready && !error && !isFetching && provider !== 'file') { + fetchManifest(manifestId); + } + } + + /** */ + handleOpenManifestSideToSide(e, manifestId) { + const { addResource, addWindow } = this.props; + addResource(manifestId); + addWindow({ manifestId }); + } + + /** */ + render() { + const { + classes, t, manifestId, thumbnail, title, description, error, ready + } = this.props; + + if (error) { + return ( + <Typography className={classes.errorMessage}>{t('resourceError', { manifestId })}</Typography> + ); + } + + if (!ready) { + return ( + <Typography> + <Typography>{t('resourceLoading')}</Typography> + </Typography> + ); + } + + return ( + <Card className={classes.root}> + <CardActionArea> + { + thumbnail && ( + <CardMedia + className={classes.thumbnail} + component="img" + height="140" + image={thumbnail} + alt="green iguana" + /> + ) + } + <CardContent> + <Typography> + { title || manifestId } + </Typography> + { + description && ( + <Typography> + { description } + </Typography> + ) + } + </CardContent> + </CardActionArea> + <CardActions> + <Tooltip title={t('openManifestInOtherWindow', { manifestId })}> + <Button + size="small" + color="primary" + onClick={(e) => { + this.handleOpenManifestSideToSide(e, manifestId); + }} + > + {t('open')} + </Button> + </Tooltip> + </CardActions> + </Card> + ); + } +} + +AnnotationManifestsItem.propsTypes = { + addResource: PropTypes.func.isRequired, + addWindow: PropTypes.func.isRequired, + classes: PropTypes.objectOf(PropTypes.string), + description: PropTypes.string, + error: PropTypes.string, + fetchManifest: PropTypes.func.isRequired, + isFetching: PropTypes.bool, + manifestLogo: PropTypes.string, + manifests: PropTypes.arrayOf(PropTypes.string), + provider: PropTypes.string, + ready: PropTypes.bool, + t: PropTypes.func.isRequired, + thumbnail: PropTypes.string, + title: PropTypes.string, +}; + +AnnotationManifestsItem.defaultProps = { + classes: {}, + error: null, + isFetching: false, + manifestLogo: null, + provider: null, + ready: false, + thumbnail: null, + title: null, +}; diff --git a/src/components/CanvasAnnotations.js b/src/components/CanvasAnnotations.js index a45baead1ec5a21b26bcbd5ad2049a0454039bf8..89ee726e6471faaf212c41ede26b04117b7c8524 100644 --- a/src/components/CanvasAnnotations.js +++ b/src/components/CanvasAnnotations.js @@ -7,8 +7,6 @@ import MenuItem from '@material-ui/core/MenuItem'; import ListItemText from '@material-ui/core/ListItemText'; import Typography from '@material-ui/core/Typography'; import SearchIcon from '@material-ui/icons/SearchSharp'; -import InputBase from '@material-ui/core/InputBase'; -import CircularProgress from '@material-ui/core/CircularProgress'; import TextField from '@material-ui/core/TextField'; import SanitizedHtml from '../containers/SanitizedHtml'; import { ScrollTo } from './ScrollTo'; diff --git a/src/containers/AnnotationManifestsAccordion.js b/src/containers/AnnotationManifestsAccordion.js index 257810aa2f135d70a8d90550bc757d21e095d57e..e9229f8ddde9d2ab58816528cb33410f679cc709 100644 --- a/src/containers/AnnotationManifestsAccordion.js +++ b/src/containers/AnnotationManifestsAccordion.js @@ -4,7 +4,6 @@ import { withTranslation } from 'react-i18next'; import { withStyles } from '@material-ui/core/styles'; import { withPlugins } from '../extend/withPlugins'; import { AnnotationManifestsAccordion } from '../components/AnnotationManifestsAccordion'; -import * as actions from '../state/actions'; import { getConfig } from '../state/selectors'; /** For connect */ @@ -18,8 +17,7 @@ const mapStateToProps = (state, { canvasId, windowId }) => ({ * @private */ const mapDispatchToProps = { - addResource: actions.addResource, - addWindow: actions.addWindow, + }; /** For withStyles */ diff --git a/src/containers/AnnotationManifestsItem.js b/src/containers/AnnotationManifestsItem.js new file mode 100644 index 0000000000000000000000000000000000000000..ad31d07b2e9ddffe7f5f7c40f4d2170f5dad4abc --- /dev/null +++ b/src/containers/AnnotationManifestsItem.js @@ -0,0 +1,67 @@ +import { compose } from 'redux'; +import { connect } from 'react-redux'; +import { withTranslation } from 'react-i18next'; +import { withStyles } from '@material-ui/core/styles'; +import { withPlugins } from '../extend/withPlugins'; +import * as actions from '../state/actions'; +import { AnnotationManifestsItem } from '../components/AnnotationManifestsItem'; +import { + getManifest, getManifestDescription, getManifestLogo, + getManifestProvider, getManifestThumbnail, getManifestTitle, + getWindowManifests, +} from '../state/selectors'; + +/** For connect */ +const mapStateToProps = (state, { manifestId }) => { + const manifest = getManifest(state, { manifestId }) || {}; + + return { + active: getWindowManifests(state) + .includes(manifestId), + description: getManifestDescription(state, { manifestId }), + error: manifest.error, + isFetching: manifest.isFetching, + manifestLogo: getManifestLogo(state, { manifestId }), + provider: getManifestProvider(state, { manifestId }), + ready: !!manifest.json, + thumbnail: getManifestThumbnail(state, { manifestId }), + title: getManifestTitle(state, { manifestId }), + }; +}; + +/** + * mapDispatchToProps - to hook up connect + * @memberof WindowSideBarAnnotationsPanel + * @private + */ +const mapDispatchToProps = { + addResource: actions.addResource, + addWindow: actions.addWindow, + fetchManifest: actions.fetchManifest, +}; + +/** For withStyles */ +const styles = theme => ({ + errorMessage: { + color: theme.palette.error.main, + }, + logo: { + height: '2.5rem', + maxWidth: '100%', + objectFit: 'contain', + paddingRight: 8, + }, + thumbnail: { + maxWidth: '100%', + objectFit: 'contain', + }, +}); + +const enhance = compose( + withTranslation(), + withStyles(styles), + connect(mapStateToProps, mapDispatchToProps), + withPlugins('AnnotationManifestsItem'), +); + +export default enhance(AnnotationManifestsItem); diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index b0f88dbeb88dc2cb0ebf24298a69d74b64815ad6..29471e77cec96dad0281ca49f372ecc5e6cfecb0 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -108,7 +108,7 @@ "openCompanionWindow_layers": "Layers", "openCompanionWindow_search": "Search", "openInCompanionWindow": "Open in separate panel", - "openManifestInOtherWindow" : "Open {{manifest}} manifest in other Mirador window", + "openManifestInOtherWindow" : "Open {{manifestId}} manifest in other Mirador window", "openWindows": "Current open windows", "pagination": "{{current}} of {{total}}", "position": "Position", @@ -116,6 +116,8 @@ "previousCanvas": "Previous item", "related": "Related", "resource": "Resource", + "resourceError": "Error when loading ressource from {{ manifestId }}", + "resourceLoading": "Loading ressource ... ", "retry": "Retry", "right": "Right", "rights": "License", diff --git a/src/locales/fr/translation.json b/src/locales/fr/translation.json index d835bed0d136fe344f1f62acbc95f94e28b50f46..45ce26156c700987ae2c0c192c1fbff6b73a17d2 100644 --- a/src/locales/fr/translation.json +++ b/src/locales/fr/translation.json @@ -104,7 +104,7 @@ "openCompanionWindow_layers": "Calques", "openCompanionWindow_search": "Rechercher", "openInCompanionWindow": "Ouvrir dans un panneau séparé", - "openManifestInOtherWindow" : "Ouvrir le manifeste dans une autre fenêtre Mirador", + "openManifestInOtherWindow" : "Ouvrir {{manifestId }} dans une autre fenêtre Mirador", "openWindows": "Fenêtres ouvertes", "pagination": "{{current}} sur {{total}}", "position": "Position", @@ -112,6 +112,8 @@ "previousCanvas": "Précédent", "related": "En relation", "resource": "Ressource", + "resourceError": "Erreur lors du changement de la ressource {{ manifestId }}", + "resourceLoading": "Chargement en cours de la ressource ... ", "retry": "Réessayer", "right": "Droite", "rights": "Licence",