Skip to content

Commit

Permalink
FEATURE: Add a comment to a film extract (closes #45).
Browse files Browse the repository at this point in the history
Co-authored-by: Enzo SIMONOVICI <enzo.simonovici@utt.fr>
  • Loading branch information
jeromeBRM and EnzoSimonoviciUTT committed Jun 4, 2024
1 parent 6b0e70f commit 58f3d99
Show file tree
Hide file tree
Showing 7 changed files with 8,700 additions and 1,350 deletions.
9,886 changes: 8,550 additions & 1,336 deletions frontend/package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"react-markdown": "^8.0.4",
"react-notifications": "^1.7.4",
"react-router-dom": "^6.4.3",
"react-youtube": "^10.1.0",
"remark-definition-list": "^2.0.0",
"remark-unwrap-images": "^4.0.0",
"uuid": "^9.0.0",
Expand Down
19 changes: 18 additions & 1 deletion frontend/src/components/EditableText.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,19 @@ import '../styles/EditableText.css';
import { useState, useEffect } from 'react';
import FormattedText from './FormattedText';

function EditableText({id, text, rubric, backend, setLastUpdate}) {
function EditableText({id, text, rubric, backend, setLastUpdate, comment}) {
const [beingEdited, setBeingEdited] = useState(false);
const [editedDocument, setEditedDocument] = useState({
text: (rubric) ? `{${rubric}} ${text}` : text
});
const PASSAGE = new RegExp(`\\{${rubric}} ?([^{]+)`);

useEffect(() => {
if (comment != '') {
handleTimecode();
}
}, [comment]);

let handleClick = () => {
setBeingEdited(true);
backend.getDocument(id)
Expand All @@ -18,6 +24,17 @@ function EditableText({id, text, rubric, backend, setLastUpdate}) {
});
};

let handleTimecode = () => {
backend.getDocument(id)
.then((editedDocument) => {
setBeingEdited(true);
let editedText = (rubric)
? editedDocument.text.replace(PASSAGE, `{${rubric}} ${editedDocument.text + comment}`)
: editedDocument.text + comment;
setEditedDocument({ ...editedDocument, text: editedText });
});
};

let handleChange = (event) => {
let editedText = (rubric)
? editedDocument.text.replace(PASSAGE, `{${rubric}} ${event.target.value}`)
Expand Down
39 changes: 34 additions & 5 deletions frontend/src/components/FormattedText.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@ import remarkUnwrapImages from 'remark-unwrap-images';
import { remarkDefinitionList, defListHastHandlers } from 'remark-definition-list';
import CroppedImage from './CroppedImage';
import VideoComment from './VideoComment';
import TimecodeBuilder from './TimecodeBuilder';
import YouTube from 'react-youtube';
import { useState } from 'react';

function FormattedText({children, addComment}) {

function FormattedText({children}) {
return (
<ReactMarkdown
remarkPlugins={[remarkDefinitionList, remarkUnwrapImages]}
components={{
img: (x) => embedVideo(x) || CroppedImage(x),
img: (x) => embedVideo({...x, addComment}) || CroppedImage(x),
p: (x) => VideoComment(x) || <p>{x.children}</p>,
a: ({children, href}) => <a href={href}>{children}</a>
}}
Expand All @@ -28,12 +32,37 @@ function getId(text) {
return match ? match[1] : null;
}

function embedVideo({src}) {
function embedVideo({src, addComment}) {
const videoId = getId(src);
const [player, setPlayer] = useState(null);

let resetCount = 0;

if (videoId) {
const embedLink = `https://www.youtube.com/embed/${videoId}`;

const opts = {
height: '300',
width: '80%',
playerVars: {
autoplay: 0,
allowFullScreen: 1
},
};

let onPlayerReady = (event) => {
if (event.target.g) {
if (resetCount == 1) {
setPlayer(event.target);
}
resetCount++;
}
};

return (
<iframe width="80%" height="300" src={embedLink} frameBorder="0" allowFullScreen></iframe>
<div key={videoId} >
<YouTube videoId={videoId} opts={opts} onReady={onPlayerReady}/>
<TimecodeBuilder player={player} addComment={addComment}></TimecodeBuilder>
</div>
);
}
return null;
Expand Down
10 changes: 9 additions & 1 deletion frontend/src/components/OpenedDocuments.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,15 @@ import Metadata from './Metadata';
import Type, { TypeBadge } from './Type';
import Passage from './Passage';

import { useState } from 'react';

function OpenedDocuments({backend, lectern, metadata, sourceMetadata, margin, setLastUpdate}) {
let [comment, setComment] = useState('');

function addComment(newText) {
setComment(newText);
}

return (
<Col className="lectern">
<Row className ="runningHead">
Expand All @@ -17,7 +25,7 @@ function OpenedDocuments({backend, lectern, metadata, sourceMetadata, margin, se
</Row>
{lectern.map(({rubric, source, scholia}, i) =>
<Passage key={rubric || i}
{...{source, rubric, scholia, margin, backend, setLastUpdate}}
{...{source, rubric, scholia, margin, backend, setLastUpdate, comment, addComment}}
/>)
}
</Col>
Expand Down
14 changes: 7 additions & 7 deletions frontend/src/components/Passage.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,30 @@ import Col from 'react-bootstrap/Col';
import FormattedText from './FormattedText';
import EditableText from '../components/EditableText';

function Passage({source, rubric, scholia, margin, backend, setLastUpdate}) {
function Passage({source, rubric, scholia, margin, backend, setLastUpdate, comment, addComment}) {
let scholium = scholia.filter(x => (x.isPartOf === margin)) || {text: ''};
return (
<Row>
<Col className="main">
<Container>
<Row>
<PassageSource>
<PassageSource addComment={addComment}>
{source}
</PassageSource>
<Rubric id={rubric} />
</Row>
</Container>
</Col>
<PassageMargin active={!!margin} {...{scholium, rubric, backend, setLastUpdate}} />
<PassageMargin active={!!margin} {...{scholium, rubric, backend, setLastUpdate, comment}} />
</Row>
);
}

function PassageSource({children}) {
function PassageSource({children, addComment}) {
return (
<Col>
{children.map((chunk, index) =>
<FormattedText key={index}>
<FormattedText key={index} addComment={addComment}>
{chunk}
</FormattedText>
)}
Expand All @@ -41,13 +41,13 @@ function Rubric({id}) {
);
}

function PassageMargin({active, scholium, rubric, backend, setLastUpdate}) {
function PassageMargin({active, scholium, rubric, backend, setLastUpdate, comment}) {
if (!active) return;
return (
<Col xs={5} className="scholium">
{scholium.map((x, i) =>
<EditableText key={i} text={x.text} id={x.id} rubric={rubric || x.rubric}
{...{backend, setLastUpdate}}
{...{backend, setLastUpdate, comment}}
/>
)}
</Col>
Expand Down
81 changes: 81 additions & 0 deletions frontend/src/components/TimecodeBuilder.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import React from 'react';
import { useEffect, useState } from 'react';

let status = 0;

function TimecodeBuilder({player, addComment}) {

let [start, setStart] = useState('0');
let [end, setEnd] = useState('0');

useEffect(() => {
if (player) {
document.body.addEventListener('keydown', logKey);
status = 0;
}
}, [player]);

useEffect(() => {
if (end != '0') {
var texte = '\n' + start + ' --> ' + end + '\n\n<TEXT>\n';
addComment(texte);
resetTimecode();
}
}, [end]);

const getPlayerTimecode = () => {
if (player) {
return player.getCurrentTime().toFixed(3).toString();
}
return 0;
};

let resetTimecode = () => {
setStart('0');
setEnd('0');
status = 0;
};

let logKey = (event) => {
console.log(event);
if (!player.g) {
return;
}

if ((event.code === 'Space' && event.ctrlKey)) {
if (status == 0) {
setStart(getTimecodeAsText());
status = 1;

} else if (status == 1) {
setEnd(getTimecodeAsText());
}
}
};

let getTimecodeAsText = () => {
var seconds = getPlayerTimecode();

var hours = Math.floor(seconds / 3600);
var minutes = Math.floor((seconds % 3600) / 60);
var remaningSeconds = Math.floor(seconds % 60);
var centiseconds = Math.floor((seconds - Math.floor(seconds)) * 1000);

var formattedHours = hours < 10 ? '0' + hours : hours;
var formattedMinutes = minutes < 10 ? '0' + minutes : minutes;
var formattedSeconds = remaningSeconds < 10 ? '0' + remaningSeconds : remaningSeconds;
var formattedCentiSecondes = centiseconds < 10 ? '00' + centiseconds : (centiseconds < 100 ? '0' + centiseconds : centiseconds);

var timecode = formattedHours + ':' + formattedMinutes + ':' + formattedSeconds + '.' + formattedCentiSecondes;

return timecode;
};

return (
<div>
{ start == 0 ? <div><p>[CTRL + SPACE] Appuyer pour marquer le début</p></div> : <div><p>{ start + ' --> [CTRL + SPACE] Appuyer pour marquer la fin' }</p><button onClick={ resetTimecode }>Réinitialiser</button></div> }
</div>
);
}

export default TimecodeBuilder;

0 comments on commit 58f3d99

Please sign in to comment.