Skip to content
Snippets Groups Projects
Commit 735afa7d authored by David Beniamine's avatar David Beniamine
Browse files

Merge branch '17-8-open-an-other-manifest-side-by-side-from-an-annotation'...

Merge branch '17-8-open-an-other-manifest-side-by-side-from-an-annotation' into 'annotation-on-video'

Manifest side to side

Closes #17

See merge request iiif/mirador-video-annotation!13
parents a9b9b6d1 0987ddf8
Branches
Tags
2 merge requests!13Manifest side to side,!9Resolve "Bug on video time control"
Pipeline #1375 passed
...@@ -3,3 +3,4 @@ coverage/ ...@@ -3,3 +3,4 @@ coverage/
node_modules/ node_modules/
*.log *.log
*.tgz *.tgz
/.idea/
Source diff could not be displayed: it is too large. Options to address this: view the blob.
import React, { Component } from 'react';
import Accordion from '@material-ui/core/Accordion';
import AccordionSummary from '@material-ui/core/AccordionSummary';
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 { removeDuplicates } from '../helper/utils';
/**
* AnnotationManifestsAccordion
*/
export class AnnotationManifestsAccordion extends Component {
/**
* constructor
*/
constructor(props) {
super(props);
this.handleOpenManifestSideToSide = this.handleOpenManifestSideToSide.bind(this);
this.handleOpenAccordion = this.handleOpenAccordion.bind(this);
/** Search manifest directly in content. We consider all the links with #manifest at the end are manifest */
function searchManifestInContent(text) {
if (text == null) {
return null;
}
return text.match(
/((http|https)\:\/\/[a-z0-9\/:%_+.,#?!@&=-]+)#manifest/gi,
);
}
/** 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(
/((http|https)\:\/\/[a-z0-9\/:%_+.,#?!@&=-]+)#((http|https)\:\/\/[a-z0-9\/:%_+.,#?!@&=-]+)/gi,
);
return match ? match[0].split('#').slice(-1) : null;
}
const { annotation } = this.props;
/** Merge array even if some are null) */
const concat = (...arrays) => [].concat(...arrays.filter(Array.isArray));
annotation.manifests = concat(searchManifestInContent(annotation.content), searchManifestInID(annotation.id));
if (annotation.manifests) {
annotation.manifests = annotation.manifests.map(id => ({ id }));
} else {
annotation.manifests = [];
}
annotation.manifests = removeDuplicates(annotation.manifests);
this.state = { annotation };
}
/** */
componentDidMount() {
const { annotation } = this.state;
/** */
async function loadManifest(manifests) {
return Promise.all(manifests.map((manifest) => fetch(manifest.id)
.then((response) => response.json())
.then((data) => {
if (data.type === 'Manifest') {
return data;
}
return null;
})));
}
loadManifest(annotation.manifests)
.then((values) => {
if (values) {
annotation.manifests = values;
this.setState({ 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) {
e.stopPropagation();
}
/** */
render() {
const {
classes, t, i18n,
} = this.props;
const language = i18n.language;
const { annotation } = this.state;
if (annotation.manifests === null || annotation.manifests.length === 0) {
return null;
}
return (
<div>
<Accordion>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
onClick={(e) => this.handleOpenAccordion(e)}
>
<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('openInCompanionWindow')}
</Button>
</Tooltip>
</CardActions>
</Card>
</Typography>
))}
</AccordionDetails>
</Accordion>
</div>
);
}
}
AnnotationManifestsAccordion.propsTypes = {
addResource: PropTypes.func.isRequired,
addWindow: PropTypes.func.isRequired,
annotation: PropTypes.shape(
{
content: PropTypes.string,
id: PropTypes.string,
manifests: PropTypes.arrayOf(PropTypes.string),
},
),
classes: PropTypes.objectOf(PropTypes.string),
t: PropTypes.func.isRequired,
};
AnnotationManifestsAccordion.defaultProps = {
classes: {},
htmlSanitizationRuleSet: 'iiif',
listContainerComponent: 'li',
};
...@@ -8,6 +8,7 @@ import ListItemText from '@material-ui/core/ListItemText'; ...@@ -8,6 +8,7 @@ import ListItemText from '@material-ui/core/ListItemText';
import Typography from '@material-ui/core/Typography'; import Typography from '@material-ui/core/Typography';
import SanitizedHtml from '../containers/SanitizedHtml'; import SanitizedHtml from '../containers/SanitizedHtml';
import { ScrollTo } from './ScrollTo'; import { ScrollTo } from './ScrollTo';
import AnnotationManifestsAccordion from '../containers/AnnotationManifestsAccordion';
/** /**
* CanvasAnnotations ~ * CanvasAnnotations ~
...@@ -63,7 +64,6 @@ export class CanvasAnnotations extends Component { ...@@ -63,7 +64,6 @@ export class CanvasAnnotations extends Component {
containerRef, containerRef,
} = this.props; } = this.props;
if (annotations.length === 0) return null; if (annotations.length === 0) return null;
return ( return (
<> <>
<Typography className={classes.sectionHeading} variant="overline"> <Typography className={classes.sectionHeading} variant="overline">
...@@ -107,6 +107,10 @@ export class CanvasAnnotations extends Component { ...@@ -107,6 +107,10 @@ export class CanvasAnnotations extends Component {
<Chip size="small" variant="outlined" label={tag} id={tag} className={classes.chip} key={tag.toString()} /> <Chip size="small" variant="outlined" label={tag} id={tag} className={classes.chip} key={tag.toString()} />
)) ))
} }
<AnnotationManifestsAccordion
annotation={annotation}
t={t}
/>
</div> </div>
</ListItemText> </ListItemText>
</MenuItem> </MenuItem>
......
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 { AnnotationManifestsAccordion } from '../components/AnnotationManifestsAccordion';
import * as actions from '../state/actions';
import { getConfig } from '../state/selectors';
/** For connect */
const mapStateToProps = (state, { canvasId, windowId }) => ({
htmlSanitizationRuleSet: getConfig(state).annotations.htmlSanitizationRuleSet,
});
/**
* mapDispatchToProps - to hook up connect
* @memberof WindowSideBarAnnotationsPanel
* @private
*/
const mapDispatchToProps = {
addResource: actions.addResource,
addWindow: actions.addWindow,
};
/** For withStyles */
const styles = theme => ({
manifestContainer: {
display: 'flex',
flexDirection: 'column',
flexWrap: 'wrap',
gap: '10px',
},
});
const enhance = compose(
withTranslation(),
withStyles(styles),
connect(mapStateToProps, mapDispatchToProps),
withPlugins('AnnotationManifestsAccordion'),
);
export default enhance(AnnotationManifestsAccordion);
...@@ -51,7 +51,7 @@ const mapDispatchToProps = { ...@@ -51,7 +51,7 @@ const mapDispatchToProps = {
selectAnnotation: actions.selectAnnotation, selectAnnotation: actions.selectAnnotation,
}; };
/** For withStlyes */ /** For withStyles */
const styles = theme => ({ const styles = theme => ({
annotationListItem: { annotationListItem: {
'&$hovered': { '&$hovered': {
...@@ -70,11 +70,15 @@ const styles = theme => ({ ...@@ -70,11 +70,15 @@ const styles = theme => ({
marginTop: theme.spacing(1), marginTop: theme.spacing(1),
}, },
hovered: {}, hovered: {},
manifestLabel: {
fontSize: '10px',
},
sectionHeading: { sectionHeading: {
paddingLeft: theme.spacing(2), paddingLeft: theme.spacing(2),
paddingRight: theme.spacing(1), paddingRight: theme.spacing(1),
paddingTop: theme.spacing(2), paddingTop: theme.spacing(2),
}, },
}); });
const enhance = compose( const enhance = compose(
......
/**
* Remove duplicate elements in array
*
* */
export const removeDuplicates = (arr) => [...new Map(arr.map(v => [v.id, v])).values()];
...@@ -81,6 +81,7 @@ ...@@ -81,6 +81,7 @@
"login": "Log in", "login": "Log in",
"logout": "Log out", "logout": "Log out",
"manifestError": "The resource cannot be added:", "manifestError": "The resource cannot be added:",
"manifestFound": "Manifests found:",
"maximizeWindow": "Maximize window", "maximizeWindow": "Maximize window",
"minimizeWindow": "Minimize window", "minimizeWindow": "Minimize window",
"mirador": "Mirador", "mirador": "Mirador",
...@@ -105,6 +106,7 @@ ...@@ -105,6 +106,7 @@
"openCompanionWindow_layers": "Layers", "openCompanionWindow_layers": "Layers",
"openCompanionWindow_search": "Search", "openCompanionWindow_search": "Search",
"openInCompanionWindow": "Open in separate panel", "openInCompanionWindow": "Open in separate panel",
"openManifestInOtherWindow" : "Open {{manifest}} manifest in other Mirador window",
"openWindows": "Current open windows", "openWindows": "Current open windows",
"pagination": "{{current}} of {{total}}", "pagination": "{{current}} of {{total}}",
"position": "Position", "position": "Position",
......
...@@ -78,6 +78,7 @@ ...@@ -78,6 +78,7 @@
"login": "Se connecter", "login": "Se connecter",
"logout": "Se déconnecter", "logout": "Se déconnecter",
"manifestError": "Cette ressource ne peut pas être ajoutée :", "manifestError": "Cette ressource ne peut pas être ajoutée :",
"manifestFound": "Manifestes trouvés:",
"maximizeWindow": "Agrandir cette fenêtre", "maximizeWindow": "Agrandir cette fenêtre",
"minimizeWindow": "Réduire cette fenêtre", "minimizeWindow": "Réduire cette fenêtre",
"mirador": "Mirador", "mirador": "Mirador",
...@@ -101,6 +102,7 @@ ...@@ -101,6 +102,7 @@
"openCompanionWindow_layers": "Calques", "openCompanionWindow_layers": "Calques",
"openCompanionWindow_search": "Rechercher", "openCompanionWindow_search": "Rechercher",
"openInCompanionWindow": "Ouvrir dans un panneau séparé", "openInCompanionWindow": "Ouvrir dans un panneau séparé",
"openManifestInOtherWindow" : "Ouvrir le manifeste dans une autre fenêtre Mirador",
"openWindows": "Fenêtres ouvertes", "openWindows": "Fenêtres ouvertes",
"pagination": "{{current}} sur {{total}}", "pagination": "{{current}} sur {{total}}",
"position": "Position", "position": "Position",
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment