Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • 5-images-in-annotations
  • 61-recettage-des-outils-d-annotation
  • 69-la-video-demare-quand-on-fait-glisser-le-slider-et-le-clic-creer-un-decalage-entre-le-player
  • 75-dernieres-ameliorations-avant-workshop-du-7-02
  • autorisation_un_pannel_annotation
  • autorisation_un_pannel_edition_annotation
  • fix-error-create-annotation-pannel
  • fix-poc-mirador
  • gestion_multiple_ouverture_pannel_annotation
  • master
  • mui5-tetras-main-old-stable
  • mui5-tetras-main-stable
  • preprod
  • récupération_temps_video
  • save-shapes-and-position
  • tetras-antho-test
  • tetras-main
  • time-saving-on-annotation
  • uploads-file
  • wip-annot-video-ui
  • wip-fix-xywh
  • wip-positionement-annot
  • wip-surface-transformer
23 results

Target

Select target project
  • lpo/mirador-annotations
1 result
Select Git revision
  • 5-images-in-annotations
  • 61-recettage-des-outils-d-annotation
  • 69-la-video-demare-quand-on-fait-glisser-le-slider-et-le-clic-creer-un-decalage-entre-le-player
  • 75-dernieres-ameliorations-avant-workshop-du-7-02
  • autorisation_un_pannel_annotation
  • autorisation_un_pannel_edition_annotation
  • fix-error-create-annotation-pannel
  • fix-poc-mirador
  • gestion_multiple_ouverture_pannel_annotation
  • master
  • mui5-tetras-main-old-stable
  • mui5-tetras-main-stable
  • preprod
  • récupération_temps_video
  • save-shapes-and-position
  • tetras-antho-test
  • tetras-main
  • time-saving-on-annotation
  • uploads-file
  • wip-annot-video-ui
  • wip-fix-xywh
  • wip-positionement-annot
  • wip-surface-transformer
23 results
Show changes

Commits on Source 25

...@@ -5,3 +5,5 @@ ...@@ -5,3 +5,5 @@
/node_modules /node_modules
/umd /umd
npm-debug.log* npm-debug.log*
.idea
16.20.2
\ No newline at end of file
...@@ -17,6 +17,7 @@ Persisting annotations requires implementing an a IIIF annotation server. Severa ...@@ -17,6 +17,7 @@ Persisting annotations requires implementing an a IIIF annotation server. Severa
`mirador-annotations` requires an instance of Mirador 3. See the [Mirador wiki](https://github.com/ProjectMirador/mirador/wiki) for examples of embedding Mirador within an application. See the [live demo's index.js](https://github.com/ProjectMirador/mirador-annotations/blob/master/demo/src/index.js) for an example of importing the `mirador-annotations` plugin and configuring the adapter. `mirador-annotations` requires an instance of Mirador 3. See the [Mirador wiki](https://github.com/ProjectMirador/mirador/wiki) for examples of embedding Mirador within an application. See the [live demo's index.js](https://github.com/ProjectMirador/mirador-annotations/blob/master/demo/src/index.js) for an example of importing the `mirador-annotations` plugin and configuring the adapter.
**You must use node v16.20.2**. You can `run nvm use` at the racine of the project to set your node version to 16.20.2.
## Contribute ## Contribute
Mirador's development, design, and maintenance is driven by community needs and ongoing feedback and discussion. Join us at our regularly scheduled community calls, on [IIIF slack #mirador](http://bit.ly/iiif-slack), or the [mirador-tech](https://groups.google.com/forum/#!forum/mirador-tech) and [iiif-discuss](https://groups.google.com/forum/#!forum/iiif-discuss) mailing lists. To suggest features, report bugs, and clarify usage, please submit a GitHub issue. Mirador's development, design, and maintenance is driven by community needs and ongoing feedback and discussion. Join us at our regularly scheduled community calls, on [IIIF slack #mirador](http://bit.ly/iiif-slack), or the [mirador-tech](https://groups.google.com/forum/#!forum/mirador-tech) and [iiif-discuss](https://groups.google.com/forum/#!forum/iiif-discuss) mailing lists. To suggest features, report bugs, and clarify usage, please submit a GitHub issue.
......
Source diff could not be displayed: it is too large. Options to address this: view the blob.
...@@ -19,13 +19,13 @@ import StrokeColorIcon from '@material-ui/icons/BorderColor'; ...@@ -19,13 +19,13 @@ import StrokeColorIcon from '@material-ui/icons/BorderColor';
import LineWeightIcon from '@material-ui/icons/LineWeight'; import LineWeightIcon from '@material-ui/icons/LineWeight';
import ArrowDropDownIcon from '@material-ui/icons/ArrowDropDown'; import ArrowDropDownIcon from '@material-ui/icons/ArrowDropDown';
import FormatShapesIcon from '@material-ui/icons/FormatShapes'; import FormatShapesIcon from '@material-ui/icons/FormatShapes';
import TextField from '@material-ui/core/TextField';
import { SketchPicker } from 'react-color'; import { SketchPicker } from 'react-color';
import { v4 as uuid } from 'uuid'; import { v4 as uuid } from 'uuid';
import { withStyles } from '@material-ui/core/styles'; import { withStyles } from '@material-ui/core/styles';
import CompanionWindow from 'mirador/dist/es/src/containers/CompanionWindow'; import CompanionWindow from 'mirador/dist/es/src/containers/CompanionWindow';
import { VideosReferences } from 'mirador/dist/es/src/plugins/VideosReferences'; import { VideosReferences } from 'mirador/dist/es/src/plugins/VideosReferences';
import { OSDReferences } from 'mirador/dist/es/src/plugins/OSDReferences'; import { OSDReferences } from 'mirador/dist/es/src/plugins/OSDReferences';
import Slider from '@material-ui/core/Slider';
import AnnotationDrawing from './AnnotationDrawing'; import AnnotationDrawing from './AnnotationDrawing';
import TextEditor from './TextEditor'; import TextEditor from './TextEditor';
import WebAnnotation from './WebAnnotation'; import WebAnnotation from './WebAnnotation';
...@@ -33,7 +33,6 @@ import CursorIcon from './icons/Cursor'; ...@@ -33,7 +33,6 @@ import CursorIcon from './icons/Cursor';
import HMSInput from './HMSInput'; import HMSInput from './HMSInput';
import ImageFormField from './ImageFormField'; import ImageFormField from './ImageFormField';
import { secondsToHMS } from './utils'; import { secondsToHMS } from './utils';
/** Extract time information from annotation target */ /** Extract time information from annotation target */
function timeFromAnnoTarget(annotarget) { function timeFromAnnoTarget(annotarget) {
console.info('TODO proper time extraction from: ', annotarget); console.info('TODO proper time extraction from: ', annotarget);
...@@ -62,7 +61,6 @@ class AnnotationCreation extends Component { ...@@ -62,7 +61,6 @@ class AnnotationCreation extends Component {
super(props); super(props);
const annoState = {}; const annoState = {};
if (props.annotation) { if (props.annotation) {
// //
// annotation body // annotation body
...@@ -136,8 +134,12 @@ class AnnotationCreation extends Component { ...@@ -136,8 +134,12 @@ class AnnotationCreation extends Component {
svg: null, svg: null,
textBody: '', textBody: '',
textEditorStateBustingKey: 0, textEditorStateBustingKey: 0,
// eslint-disable-next-line sort-keys,max-len
// TO DO : The state must be updated with the video's timing information when the component is mounted
valueTime: [0, 1],
xywh: null, xywh: null,
...annoState, ...annoState,
valuetextTime: '',
}; };
this.submitForm = this.submitForm.bind(this); this.submitForm = this.submitForm.bind(this);
...@@ -159,6 +161,8 @@ class AnnotationCreation extends Component { ...@@ -159,6 +161,8 @@ class AnnotationCreation extends Component {
this.closeChooseColor = this.closeChooseColor.bind(this); this.closeChooseColor = this.closeChooseColor.bind(this);
this.updateStrokeColor = this.updateStrokeColor.bind(this); this.updateStrokeColor = this.updateStrokeColor.bind(this);
this.handleImgChange = this.handleImgChange.bind(this); this.handleImgChange = this.handleImgChange.bind(this);
this.handleChangeTime = this.handleChangeTime.bind(this);
this.valuetextTime = this.valuetextTime.bind(this);
} }
/** */ /** */
...@@ -196,16 +200,23 @@ class AnnotationCreation extends Component { ...@@ -196,16 +200,23 @@ class AnnotationCreation extends Component {
this.setState({ tend: Math.floor(this.props.currentTime) }); this.setState({ tend: Math.floor(this.props.currentTime) });
} }
handleChangeTime = (event, newValueTime) => {
const timeStart = newValueTime[0];
const timeEnd = newValueTime[1];
this.updateTstart(timeStart);
this.updateTend(timeEnd);
this.seekToTstart();
this.seekToTend();
this.setState({ valueTime: newValueTime });
};
/** update annotation start time */
updateTstart(value) { this.setState({ tstart: value }); }
/** update annotation end time */
updateTend(value) { this.setState({ tend: value }); }
/** seekTo/goto annotation start time */ /** seekTo/goto annotation start time */
seekToTstart() {
const { paused, setCurrentTime, setSeekTo } = this.props;
const { tstart } = this.state;
if (!paused) {
this.setState(setSeekTo(tstart));
} else {
this.setState(setCurrentTime(tstart));
}
}
/** seekTo/goto annotation end time */ /** seekTo/goto annotation end time */
seekToTend() { seekToTend() {
...@@ -218,11 +229,21 @@ class AnnotationCreation extends Component { ...@@ -218,11 +229,21 @@ class AnnotationCreation extends Component {
} }
} }
/** update annotation start time */ // eslint-disable-next-line require-jsdoc
updateTstart(value) { this.setState({ tstart: value }); } seekToTstart() {
const { paused, setCurrentTime, setSeekTo } = this.props;
const { tstart } = this.state;
if (!paused) {
this.setState(setSeekTo(tstart));
} else {
this.setState(setCurrentTime(tstart));
}
}
/** update annotation end time */ // eslint-disable-next-line require-jsdoc
updateTend(value) { this.setState({ tend: value }); } valuetextTime() {
return this.valueTime;
}
/** */ /** */
openChooseColor(e) { openChooseColor(e) {
...@@ -342,10 +363,17 @@ class AnnotationCreation extends Component { ...@@ -342,10 +363,17 @@ class AnnotationCreation extends Component {
activeTool, colorPopoverOpen, currentColorType, fillColor, popoverAnchorEl, activeTool, colorPopoverOpen, currentColorType, fillColor, popoverAnchorEl,
strokeColor, popoverLineWeightAnchorEl, lineWeightPopoverOpen, strokeWidth, closedMode, strokeColor, popoverLineWeightAnchorEl, lineWeightPopoverOpen, strokeWidth, closedMode,
textBody, svg, tstart, tend, textBody, svg, tstart, tend,
textEditorStateBustingKey, image, textEditorStateBustingKey, image, valueTime,
} = this.state; } = this.state;
let mediaVideo;
// TODO : Vérifier ce code, c'est étrange de comprarer un typeof à une chaine de caractère.
const mediaIsVideo = typeof VideosReferences.get(windowId) !== 'undefined'; const mediaIsVideo = typeof VideosReferences.get(windowId) !== 'undefined';
if (mediaIsVideo) {
mediaVideo = VideosReferences.get(windowId);
valueTime[0] = tstart;
valueTime[1] = tend;
}
return ( return (
<CompanionWindow <CompanionWindow
...@@ -366,6 +394,97 @@ class AnnotationCreation extends Component { ...@@ -366,6 +394,97 @@ class AnnotationCreation extends Component {
player={mediaIsVideo ? VideosReferences.get(windowId) : OSDReferences.get(windowId)} player={mediaIsVideo ? VideosReferences.get(windowId) : OSDReferences.get(windowId)}
/> />
<form onSubmit={this.submitForm} className={classes.section}> <form onSubmit={this.submitForm} className={classes.section}>
<div>
<Grid item xs={12}>
<Typography variant="overline">
Text Content
</Typography>
</Grid>
<Grid item xs={12}>
<TextEditor
key={textEditorStateBustingKey}
annoHtml={textBody}
updateAnnotationBody={this.updateTextBody}
/>
</Grid>
</div>
<div>
{ mediaIsVideo && (
<>
<Grid item xs={12} className={classes.paper}>
<Typography id="range-slider" variant="overline">
Display period
</Typography>
{/* <Typography>
{mediaIsVideo ? mediaVideo?.video.duration : null}
</Typography> */}
<Slider
value={valueTime}
onChange={this.handleChangeTime}
valueLabelDisplay="auto"
aria-labelledby="range-slider"
getAriaValueText={secondsToHMS}
max={mediaVideo ? mediaVideo.video.duration : null}
color="secondary"
classes={{
root: classes.MuiSliderColorSecondary,
}}
/>
</Grid>
<div className={`${classes.paper} ${classes.selectTimeField} `}>
<div className={`${classes.paper} ${classes.selectTimeModule} `}>
<div className={classes.buttonTimeContainer}>
<div>
<p className={classes.textTimeButton}>Start</p>
</div>
<ToggleButton
value="true"
title="Set current time"
size="small"
onClick={this.setTstartNow}
className={classes.timecontrolsbutton}
>
<Alarm fontSize="small" />
</ToggleButton>
</div>
<HMSInput seconds={tstart} onChange={this.updateTstart} />
</div>
<div className={`${classes.paper} ${classes.selectTimeModule}`}>
<div className={classes.buttonTimeContainer}>
<div>
<p className={classes.textTimeButton}>End</p>
</div>
<ToggleButton
value="true"
title="Set current time"
size="small"
onClick={this.setTendNow}
className={classes.timecontrolsbutton}
>
<Alarm fontSize="small" />
</ToggleButton>
</div>
<HMSInput seconds={tend} onChange={this.updateTend} />
</div>
</div>
</>
)}
</div>
<div>
<Grid container>
<Grid item xs={12}>
<Typography variant="overline">
Image Content
</Typography>
</Grid>
<Grid item xs={12} style={{ marginBottom: 10 }}>
<ImageFormField value={image} onChange={this.handleImgChange} />
</Grid>
</Grid>
</div>
<div>
<Grid container> <Grid container>
<Grid item xs={12}> <Grid item xs={12}>
<Typography variant="overline"> <Typography variant="overline">
...@@ -414,6 +533,8 @@ class AnnotationCreation extends Component { ...@@ -414,6 +533,8 @@ class AnnotationCreation extends Component {
</Paper> </Paper>
</Grid> </Grid>
</Grid> </Grid>
</div>
<div>
<Grid container> <Grid container>
<Grid item xs={12}> <Grid item xs={12}>
<Typography variant="overline"> <Typography variant="overline">
...@@ -472,69 +593,15 @@ class AnnotationCreation extends Component { ...@@ -472,69 +593,15 @@ class AnnotationCreation extends Component {
} }
</Grid> </Grid>
</Grid> </Grid>
<Grid container> </div>
{ mediaIsVideo && ( <div>
<>
<Grid item xs={12}>
<ToggleButton value="true" title="Go to start time" size="small" onClick={this.seekToTstart} className={classes.timecontrolsbutton}>
<LastPage />
</ToggleButton>
<Typography variant="overline">
Start
</Typography>
</Grid>
<Grid item xs={12} className={classes.paper}>
<ToggleButton value="true" title="Set current time" size="small" onClick={this.setTstartNow} className={classes.timecontrolsbutton}>
<Alarm />
</ToggleButton>
<HMSInput seconds={tstart} onChange={this.updateTstart} />
</Grid>
<Grid item xs={12}>
<Typography variant="overline">
<ToggleButton value="true" title="Go to end time" size="small" onClick={this.seekToTend} className={classes.timecontrolsbutton}>
<LastPage />
</ToggleButton>
End
</Typography>
</Grid>
<Grid item xs={12} className={classes.paper}>
<ToggleButton value="true" title="Set current time" size="small" onClick={this.setTendNow} className={classes.timecontrolsbutton}>
<Alarm />
</ToggleButton>
<HMSInput seconds={tend} onChange={this.updateTend} />
</Grid>
</>
)}
<Grid item xs={12}>
<Typography variant="overline">
Image Content
</Typography>
</Grid>
<Grid item xs={12} style={{ marginBottom: 10 }}>
<ImageFormField value={image} onChange={this.handleImgChange} />
</Grid>
<Grid item xs={12}>
<Typography variant="overline">
Text Content
</Typography>
</Grid>
<Grid item xs={12}>
<TextEditor
key={textEditorStateBustingKey}
annoHtml={textBody}
updateAnnotationBody={this.updateTextBody}
/>
</Grid>
</Grid>
<Button onClick={closeCompanionWindow}> <Button onClick={closeCompanionWindow}>
Cancel Cancel
</Button> </Button>
<Button variant="contained" color="primary" type="submit"> <Button variant="contained" color="primary" type="submit">
Save Save
</Button> </Button>
</div>
</form> </form>
<Popover <Popover
open={lineWeightPopoverOpen} open={lineWeightPopoverOpen}
...@@ -574,9 +641,12 @@ class AnnotationCreation extends Component { ...@@ -574,9 +641,12 @@ class AnnotationCreation extends Component {
); );
} }
} }
/** */ /** */
const styles = (theme) => ({ const styles = (theme) => ({
buttonTimeContainer: {
display: 'flex',
flexDirection: 'column',
},
divider: { divider: {
margin: theme.spacing(1, 0.5), margin: theme.spacing(1, 0.5),
}, },
...@@ -590,22 +660,48 @@ const styles = (theme) => ({ ...@@ -590,22 +660,48 @@ const styles = (theme) => ({
border: 'none', border: 'none',
margin: theme.spacing(0.5), margin: theme.spacing(0.5),
}, },
MuiSliderColorSecondary: {
color: 'rgba(1, 0, 0, 0.38)',
},
paper: { paper: {
display: 'flex', display: 'flex',
flexWrap: 'wrap', flexWrap: 'wrap',
}, },
section: { section: {
display: 'flex',
flexDirection: 'column',
gap: '20px',
paddingBottom: theme.spacing(1), paddingBottom: theme.spacing(1),
paddingLeft: theme.spacing(2), paddingLeft: theme.spacing(2),
paddingRight: theme.spacing(1), paddingRight: theme.spacing(1),
paddingTop: theme.spacing(2), paddingTop: theme.spacing(2),
}, },
selectTimeField: {
alignContent: 'center',
display: 'flex',
flexDirection: 'wrap',
gap: '5px',
padding: '5px',
},
selectTimeModule: {
border: '1px solid rgba(0, 0, 0, 0.12)',
borderRadius: '4px',
display: 'flex',
flexWrap: 'nowrap',
justifyContent: 'center',
padding: '5px',
},
textTimeButton: {
fontSize: '15px',
margin: 0,
minWidth: '40px',
},
timecontrolsbutton: { timecontrolsbutton: {
border: 'none',
height: '30px', height: '30px',
margin: 'auto', margin: 'auto',
marginLeft: '0', marginLeft: '0',
marginRight: '5px', marginRight: '5px',
width: '30px',
}, },
}); });
......
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles'; import { withStyles } from '@material-ui/core/styles';
import { IconButton, Input } from '@material-ui/core'; import { IconButton, Input, TextField } from '@material-ui/core';
import { ArrowDownward, ArrowUpward } from '@material-ui/icons'; import { ArrowDownward, ArrowUpward } from '@material-ui/icons';
import { secondsToHMSarray } from './utils'; import { secondsToHMSarray } from './utils';
...@@ -18,10 +18,7 @@ class HMSInput extends Component { ...@@ -18,10 +18,7 @@ class HMSInput extends Component {
minutes: m, minutes: m,
seconds: s, seconds: s,
}; };
this.someChange = this.someChange.bind(this); this.someChange = this.someChange.bind(this);
this.addOneSec = this.addOneSec.bind(this);
this.subOneSec = this.subOneSec.bind(this);
} }
/** update */ /** update */
...@@ -44,18 +41,6 @@ class HMSInput extends Component { ...@@ -44,18 +41,6 @@ class HMSInput extends Component {
onChange(state.hours * 3600 + state.minutes * 60 + state.seconds); onChange(state.hours * 3600 + state.minutes * 60 + state.seconds);
} }
/** Add one second by simulating an input change */
addOneSec() {
const { seconds } = this.state;
this.someChange({ target: { name: 'seconds', value: seconds + 1 } });
}
/** Substract one second by simulating an input change */
subOneSec() {
const { seconds } = this.state;
this.someChange({ target: { name: 'seconds', value: seconds - 1 } });
}
/** Render */ /** Render */
render() { render() {
const { hours, minutes, seconds } = this.state; const { hours, minutes, seconds } = this.state;
...@@ -63,17 +48,22 @@ class HMSInput extends Component { ...@@ -63,17 +48,22 @@ class HMSInput extends Component {
return ( return (
<div className={classes.root}> <div className={classes.root}>
<div className={classes.root}> <div className={classes.root}>
<Input className={classes.input} name="hours" value={hours} onChange={this.someChange} /> <Input
<Input className={classes.input} name="minutes" value={minutes} onChange={this.someChange} /> className={classes.input}
<Input className={classes.input} name="seconds" value={seconds} onChange={this.someChange} /> variant="filled"
</div> type="number"
<div className={classes.flexcol}> min="0"
<IconButton size="small" onClick={this.addOneSec}> pattern
<ArrowUpward /> name="hours"
</IconButton> value={hours}
<IconButton size="small" onClick={this.subOneSec}> onChange={this.someChange}
<ArrowDownward /> inputProps={{ style: { textAlign: 'center' } }}
</IconButton> />
<span className={classes.hmsLabel}>h</span>
<Input className={classes.input} type="number" min="0" max="59" name="minutes" value={minutes} onChange={this.someChange} inputProps={{ style: { textAlign: 'center' } }} />
<span className={classes.hmsLabel}>m</span>
<Input className={classes.input} type="number" min="0" max="59" name="seconds" value={seconds} onChange={this.someChange} inputProps={{ style: { textAlign: 'center' } }} />
<span className={classes.hmsLabel}>s</span>
</div> </div>
</div> </div>
); );
...@@ -85,7 +75,6 @@ const styles = (theme) => ({ ...@@ -85,7 +75,6 @@ const styles = (theme) => ({
root: { root: {
alignItems: 'center', alignItems: 'center',
display: 'flex', display: 'flex',
justifyContent: 'end',
}, },
// eslint-disable-next-line sort-keys // eslint-disable-next-line sort-keys
flexcol: { flexcol: {
...@@ -93,12 +82,26 @@ const styles = (theme) => ({ ...@@ -93,12 +82,26 @@ const styles = (theme) => ({
flexDirection: 'column', flexDirection: 'column',
justifyContent: 'center', justifyContent: 'center',
}, },
hmsLabel: {
color: 'grey',
},
// eslint-disable-next-line sort-keys // eslint-disable-next-line sort-keys
input: { input: {
height: 'fit-content', height: 'fit-content',
margin: '2px', margin: '2px',
textAlign: 'center', // remove arrow from field for Firefox
width: '4ch', '& input[type=number]': {
'-moz-appearance': 'textfield',
},
// remove arrow from field for Chrome, Safari and Opera
'& input[type=number]::-webkit-outer-spin-button': {
'-webkit-appearance': 'none',
margin: 0,
},
'& input[type=number]::-webkit-inner-spin-button': {
'-webkit-appearance': 'none',
margin: 0,
},
}, },
}); });
......
...@@ -71,6 +71,14 @@ class TextEditor extends Component { ...@@ -71,6 +71,14 @@ class TextEditor extends Component {
return ( return (
<div> <div>
<div className={classes.editorRoot} onClick={this.handleFocus}>
<Editor
editorState={editorState}
handleKeyCommand={this.handleKeyCommand}
onChange={this.onChange}
ref={this.editorRef}
/>
</div>
<ToggleButtonGroup <ToggleButtonGroup
size="small" size="small"
value={currentStyle.toArray()} value={currentStyle.toArray()}
...@@ -88,15 +96,6 @@ class TextEditor extends Component { ...@@ -88,15 +96,6 @@ class TextEditor extends Component {
<ItalicIcon/> <ItalicIcon/>
</ToggleButton> </ToggleButton>
</ToggleButtonGroup> </ToggleButtonGroup>
<div className={classes.editorRoot} onClick={this.handleFocus}>
<Editor
editorState={editorState}
handleKeyCommand={this.handleKeyCommand}
onChange={this.onChange}
ref={this.editorRef}
/>
</div>
</div> </div>
); );
} }
......