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 @@
/node_modules
/umd
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
`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
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.
......
This diff is collapsed.
......@@ -19,13 +19,13 @@ import StrokeColorIcon from '@material-ui/icons/BorderColor';
import LineWeightIcon from '@material-ui/icons/LineWeight';
import ArrowDropDownIcon from '@material-ui/icons/ArrowDropDown';
import FormatShapesIcon from '@material-ui/icons/FormatShapes';
import TextField from '@material-ui/core/TextField';
import { SketchPicker } from 'react-color';
import { v4 as uuid } from 'uuid';
import { withStyles } from '@material-ui/core/styles';
import CompanionWindow from 'mirador/dist/es/src/containers/CompanionWindow';
import { VideosReferences } from 'mirador/dist/es/src/plugins/VideosReferences';
import { OSDReferences } from 'mirador/dist/es/src/plugins/OSDReferences';
import Slider from '@material-ui/core/Slider';
import AnnotationDrawing from './AnnotationDrawing';
import TextEditor from './TextEditor';
import WebAnnotation from './WebAnnotation';
......@@ -33,7 +33,6 @@ import CursorIcon from './icons/Cursor';
import HMSInput from './HMSInput';
import ImageFormField from './ImageFormField';
import { secondsToHMS } from './utils';
/** Extract time information from annotation target */
function timeFromAnnoTarget(annotarget) {
console.info('TODO proper time extraction from: ', annotarget);
......@@ -62,7 +61,6 @@ class AnnotationCreation extends Component {
super(props);
const annoState = {};
if (props.annotation) {
//
// annotation body
......@@ -136,8 +134,12 @@ class AnnotationCreation extends Component {
svg: null,
textBody: '',
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,
...annoState,
valuetextTime: '',
};
this.submitForm = this.submitForm.bind(this);
......@@ -159,6 +161,8 @@ class AnnotationCreation extends Component {
this.closeChooseColor = this.closeChooseColor.bind(this);
this.updateStrokeColor = this.updateStrokeColor.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 {
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 */
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 */
seekToTend() {
......@@ -218,11 +229,21 @@ class AnnotationCreation extends Component {
}
}
/** update annotation start time */
updateTstart(value) { this.setState({ tstart: value }); }
// eslint-disable-next-line require-jsdoc
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 */
updateTend(value) { this.setState({ tend: value }); }
// eslint-disable-next-line require-jsdoc
valuetextTime() {
return this.valueTime;
}
/** */
openChooseColor(e) {
......@@ -342,10 +363,17 @@ class AnnotationCreation extends Component {
activeTool, colorPopoverOpen, currentColorType, fillColor, popoverAnchorEl,
strokeColor, popoverLineWeightAnchorEl, lineWeightPopoverOpen, strokeWidth, closedMode,
textBody, svg, tstart, tend,
textEditorStateBustingKey, image,
textEditorStateBustingKey, image, valueTime,
} = 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';
if (mediaIsVideo) {
mediaVideo = VideosReferences.get(windowId);
valueTime[0] = tstart;
valueTime[1] = tend;
}
return (
<CompanionWindow
......@@ -366,6 +394,97 @@ class AnnotationCreation extends Component {
player={mediaIsVideo ? VideosReferences.get(windowId) : OSDReferences.get(windowId)}
/>
<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 item xs={12}>
<Typography variant="overline">
......@@ -414,6 +533,8 @@ class AnnotationCreation extends Component {
</Paper>
</Grid>
</Grid>
</div>
<div>
<Grid container>
<Grid item xs={12}>
<Typography variant="overline">
......@@ -472,69 +593,15 @@ class AnnotationCreation extends Component {
}
</Grid>
</Grid>
<Grid container>
{ mediaIsVideo && (
<>
<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>
</div>
<div>
<Button onClick={closeCompanionWindow}>
Cancel
</Button>
<Button variant="contained" color="primary" type="submit">
Save
</Button>
</div>
</form>
<Popover
open={lineWeightPopoverOpen}
......@@ -574,9 +641,12 @@ class AnnotationCreation extends Component {
);
}
}
/** */
const styles = (theme) => ({
buttonTimeContainer: {
display: 'flex',
flexDirection: 'column',
},
divider: {
margin: theme.spacing(1, 0.5),
},
......@@ -590,22 +660,48 @@ const styles = (theme) => ({
border: 'none',
margin: theme.spacing(0.5),
},
MuiSliderColorSecondary: {
color: 'rgba(1, 0, 0, 0.38)',
},
paper: {
display: 'flex',
flexWrap: 'wrap',
},
section: {
display: 'flex',
flexDirection: 'column',
gap: '20px',
paddingBottom: theme.spacing(1),
paddingLeft: theme.spacing(2),
paddingRight: theme.spacing(1),
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: {
border: 'none',
height: '30px',
margin: 'auto',
marginLeft: '0',
marginRight: '5px',
width: '30px',
},
});
......
import React, { Component } from 'react';
import PropTypes from 'prop-types';
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 { secondsToHMSarray } from './utils';
......@@ -18,10 +18,7 @@ class HMSInput extends Component {
minutes: m,
seconds: s,
};
this.someChange = this.someChange.bind(this);
this.addOneSec = this.addOneSec.bind(this);
this.subOneSec = this.subOneSec.bind(this);
}
/** update */
......@@ -44,18 +41,6 @@ class HMSInput extends Component {
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() {
const { hours, minutes, seconds } = this.state;
......@@ -63,17 +48,22 @@ class HMSInput extends Component {
return (
<div className={classes.root}>
<div className={classes.root}>
<Input className={classes.input} name="hours" value={hours} onChange={this.someChange} />
<Input className={classes.input} name="minutes" value={minutes} onChange={this.someChange} />
<Input className={classes.input} name="seconds" value={seconds} onChange={this.someChange} />
</div>
<div className={classes.flexcol}>
<IconButton size="small" onClick={this.addOneSec}>
<ArrowUpward />
</IconButton>
<IconButton size="small" onClick={this.subOneSec}>
<ArrowDownward />
</IconButton>
<Input
className={classes.input}
variant="filled"
type="number"
min="0"
pattern
name="hours"
value={hours}
onChange={this.someChange}
inputProps={{ style: { textAlign: 'center' } }}
/>
<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>
);
......@@ -85,7 +75,6 @@ const styles = (theme) => ({
root: {
alignItems: 'center',
display: 'flex',
justifyContent: 'end',
},
// eslint-disable-next-line sort-keys
flexcol: {
......@@ -93,12 +82,26 @@ const styles = (theme) => ({
flexDirection: 'column',
justifyContent: 'center',
},
hmsLabel: {
color: 'grey',
},
// eslint-disable-next-line sort-keys
input: {
height: 'fit-content',
margin: '2px',
textAlign: 'center',
width: '4ch',
// remove arrow from field for Firefox
'& 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 {
return (
<div>
<div className={classes.editorRoot} onClick={this.handleFocus}>
<Editor
editorState={editorState}
handleKeyCommand={this.handleKeyCommand}
onChange={this.onChange}
ref={this.editorRef}
/>
</div>
<ToggleButtonGroup
size="small"
value={currentStyle.toArray()}
......@@ -88,15 +96,6 @@ class TextEditor extends Component {
<ItalicIcon/>
</ToggleButton>
</ToggleButtonGroup>
<div className={classes.editorRoot} onClick={this.handleFocus}>
<Editor
editorState={editorState}
handleKeyCommand={this.handleKeyCommand}
onChange={this.onChange}
ref={this.editorRef}
/>
</div>
</div>
);
}
......