fix selection (for good?)

This commit is contained in:
Sara
2023-12-12 11:36:40 +01:00
parent 369a16b4a5
commit 4d5d76fe8f
3 changed files with 98 additions and 30 deletions

View File

@@ -4,7 +4,6 @@ import { useEffect, useRef, useState } from "react";
import { Participant } from "../../../../api";
import getApi from "../../../../lib/getApi";
import { UseParticipants } from "../../useParticipants";
import { unescapeLeadingUnderscores } from "typescript";
type ParticipantList = {
participants: UseParticipants;
@@ -27,6 +26,7 @@ const ParticipantList = ({
const [participantInput, setParticipantInput] = useState("");
const inputRef = useRef<HTMLInputElement>(null);
const [selectedSpeaker, setSelectedSpeaker] = stateSelectedSpeaker;
const [selectedParticipant, setSelectedParticipant] = useState<Participant>();
const [action, setAction] = useState<
"Create" | "Create to rename" | "Create and assign" | "Rename" | null
>(null);
@@ -47,9 +47,11 @@ const ParticipantList = ({
);
if (participant) {
setParticipantInput(participant.name);
setSelectedParticipant(participant);
inputRef.current?.focus();
setAction("Rename");
} else {
} else if (!selectedParticipant) {
setSelectedParticipant(undefined);
setParticipantInput("");
inputRef.current?.focus();
setAction("Create to rename");
@@ -59,6 +61,10 @@ const ParticipantList = ({
setParticipantInput("");
inputRef.current?.focus();
setAction("Create and assign");
setSelectedParticipant(undefined);
}
if (!selectedTime && !selectedSpeaker) {
setAction(null);
}
}
}, [selectedTime, selectedSpeaker]);
@@ -78,6 +84,12 @@ const ParticipantList = ({
setOneMatch(undefined);
}
}
if (participantInput && !action) {
setAction("Create");
}
if (!participantInput) {
setAction(null);
}
}, [participantInput]);
useEffect(() => {
@@ -88,11 +100,15 @@ const ParticipantList = ({
setOneMatch(undefined);
setParticipantInput("");
}
} else if (e.key === "Enter") {
doAction();
}
};
});
const doAction = (e) => {
const doAction = (e?) => {
e?.preventDefault();
e?.stopPropagation();
if (!participants.response) return;
if (action == "Rename") {
const participant = participants.response.find(
@@ -124,6 +140,7 @@ const ParticipantList = ({
})
.then(() => {
participants.refetch();
setParticipantInput("");
});
} else if (action == "Create and assign") {
setLoading(true);
@@ -138,11 +155,22 @@ const ParticipantList = ({
.then((participant) => {
assignTo(participant)();
participants.refetch();
setParticipantInput("");
});
} else if (action == "Create") {
setLoading(true);
api
?.v1TranscriptAddParticipant({
createParticipant: {
name: participantInput,
},
transcriptId,
})
.then(() => {
participants.refetch();
setParticipantInput("");
});
}
e.preventDefault();
console.log(e);
console.log(action);
};
const deleteParticipant = (participantId) => () => {
@@ -162,6 +190,7 @@ const ParticipantList = ({
(participant) => (e?: React.MouseEvent<HTMLButtonElement>) => {
e?.preventDefault();
e?.stopPropagation();
// fix participant that doesnt have a speaker (wait API)
if (selectedTime?.start == undefined || selectedTime?.end == undefined)
return;
api
@@ -179,22 +208,29 @@ const ParticipantList = ({
};
const selectParticipant = (participant) => (e) => {
console.log(participant, e);
setSelectedParticipant(participant);
setSelectedSpeaker(participant.speaker);
setAction("Rename");
setParticipantInput(participant.name);
};
return (
<>
<form onSubmit={doAction}>
<div>
<input
ref={inputRef}
onChange={(e) => setParticipantInput(e.target.value)}
value={participantInput}
/>
<button type="submit">
<FontAwesomeIcon icon={faArrowTurnDown} className="rotate-90 mr-2" />
{action && (
<button onClick={doAction}>
<FontAwesomeIcon
icon={faArrowTurnDown}
className="rotate-90 mr-2"
/>
{action}
</button>
</form>
)}
</div>
{participants.loading && (
<FontAwesomeIcon
@@ -214,7 +250,7 @@ const ParticipantList = ({
participant.name.startsWith(participantInput)
? "bg-blue-100 "
: "") +
(participant.speaker == selectedSpeaker
(participant.id == selectedParticipant?.id
? "border-blue-400 border"
: "")
}

View File

@@ -9,6 +9,7 @@ const TopicPlayer = ({ transcriptId, selectedTime, topicTime }) => {
useState<() => void>();
//TODO shortcuts
// TODO if selection changes while playing, don't play
useEffect(() => {
setEndTopicCallback(

View File

@@ -12,7 +12,7 @@ type Word = {
type WordBySpeaker = { speaker: number; words: Word[] }[];
// TODO shortcuts
// TODO shortcuts ?
// TODO fix key (using indexes might act up, not sure as we don't re-order per say)
type TopicWordsProps = {
@@ -63,6 +63,25 @@ const topicWords = ({
}
}, [topicWithWords.response]);
const getStartTimeFromFirstNode = (node, offset, reverse) => {
// if the first element is a word
return node.parentElement?.dataset["start"]
? // but after of the word (like on the blank space right of the word)
node.textContent?.length == offset
? // if next element is a word, we need the start of it
(node.parentElement?.nextElementSibling as any)?.dataset?.["start"] ||
// otherwise we get the start of the first word of the next paragraph
(
node.parentElement?.parentElement?.nextElementSibling
?.childNodes[1] as any
)?.dataset?.["start"] ||
(reverse ? 0 : 99)
: // otherwise it's just somewhere in the word and we get the start of the word
node.parentElement?.dataset["start"]
: // otherwise selection start is on a name and we get the start of the next word
(node.parentElement?.nextElementSibling as any)?.dataset["start"];
};
const onMouseUp = (e) => {
let selection = window.getSelection();
if (
@@ -102,35 +121,47 @@ const topicWords = ({
return;
}
const anchorStart = anchorIsWord
? anchorNode.parentElement?.dataset["start"]
: (selection.anchorNode.parentElement?.nextElementSibling as any)
?.dataset["start"];
const anchorStart = getStartTimeFromFirstNode(
anchorNode,
selection.anchorOffset,
false,
);
// if selection end on a word, we get the end time from the span that contains it
const focusEnd =
selection.focusNode.parentElement?.dataset["end"] ||
// otherwise it was a name and we get the end of the last word of the previous paragraph
(
selection.focusNode.parentElement?.parentElement
?.previousElementSibling?.lastElementChild as any
)?.dataset["end"];
)?.dataset["end"] ||
0;
const reverse = parseFloat(anchorStart) > parseFloat(focusEnd);
if (!reverse) {
setSelectedTime({ start: anchorStart, end: focusEnd });
setSelectedTime({
start: parseFloat(anchorStart),
end: parseFloat(focusEnd),
});
console.log("setting right");
} else {
const anchorEnd = anchorIsWord
? anchorNode.parentElement?.dataset["end"]
: (selection.anchorNode.parentElement?.nextElementSibling as any)
?.dataset["end"];
const focusStart =
selection.focusNode.parentElement?.dataset["start"] ||
const anchorEnd =
anchorNode.parentElement?.dataset["end"] ||
(
selection.focusNode.parentElement?.parentElement
selection.anchorNode.parentElement?.parentElement
?.previousElementSibling?.lastElementChild as any
)?.dataset["start"];
)?.dataset["end"];
const focusStart = getStartTimeFromFirstNode(
focusNode,
selection.focusOffset,
true,
);
setSelectedTime({ start: focusStart, end: anchorEnd });
console.log("setting reverse");
}
setSelectedSpeaker();
selection.empty();
}
@@ -147,7 +178,7 @@ const topicWords = ({
if (!topicWithWords.loading && wordsBySpeaker && participants.response) {
return (
<div onMouseUp={onMouseUp} onBlur={(e) => console.log(e)}>
<div onMouseUp={onMouseUp} className="p-5 h-full w-full">
{wordsBySpeaker?.map((speakerWithWords, index) => (
<p key={index}>
<span