399 lines
10 KiB
JavaScript
399 lines
10 KiB
JavaScript
import { useState } from "react";
|
|
import "./VerseValidator.css";
|
|
import { StringDiff } from "react-string-diff";
|
|
import { containsKorean, jamoSubstringMatch } from './utils';
|
|
|
|
const STATE = {
|
|
INCORRECT: 0,
|
|
PARTIAL: 1,
|
|
CORRECT: 2,
|
|
};
|
|
|
|
|
|
|
|
// function to render and handle logic of each of the cells
|
|
const VerseValidator = ({ element: { pack, title, chapterTitle, reference, verse } , toHideReference, t, index}) => { // useful use of destructuring here
|
|
|
|
const [inputReference, setReference] = useState('')
|
|
const [referenceBool, setReferenceBool] = useState(STATE.INCORRECT)
|
|
const [inputChapterTitle, setChapterTitle] = useState('')
|
|
const [chapterTitleBool, setChapterTitleBool] = useState(STATE.INCORRECT)
|
|
const [inputTitle, setTitle] = useState('')
|
|
const [titleBool, setTitleBool] = useState(STATE.INCORRECT)
|
|
const [inputVerse, setVerse] = useState('')
|
|
const [verseBool, setVerseBool] = useState(STATE.INCORRECT)
|
|
const[hintBool, setHintBool] = useState(false)
|
|
const[diffBool, setDiffBool] = useState(false)
|
|
const [isComposing, setIsComposing] = useState(false);
|
|
|
|
// handle reset
|
|
const handleReset = () => {
|
|
setReference('');
|
|
setReferenceBool(STATE.INCORRECT);
|
|
setChapterTitle('');
|
|
setChapterTitleBool(STATE.INCORRECT);
|
|
setTitle('');
|
|
setTitleBool(STATE.INCORRECT);
|
|
setVerse('');
|
|
setVerseBool(STATE.INCORRECT);
|
|
setDiffBool(false); // optionally hide answer again
|
|
};
|
|
|
|
|
|
|
|
// Handle the start of composition
|
|
const handleCompositionStart = () => {
|
|
setIsComposing(true);
|
|
};
|
|
|
|
function resultChecker(string1, string2) {
|
|
var result = STATE.INCORRECT; // init
|
|
// contains korean
|
|
if (containsKorean(string1)) {
|
|
if (string1 === string2) {
|
|
result = STATE.CORRECT;
|
|
} else if (jamoSubstringMatch(string2, string1) & string1 !== "") {
|
|
result = STATE.PARTIAL;
|
|
} else {
|
|
result = STATE.INCORRECT;
|
|
}
|
|
} else { // does not contain korean
|
|
if (string1 === string2) {
|
|
result = STATE.CORRECT;
|
|
} else if (string2.startsWith(string1) & string1 !== "") {
|
|
result = STATE.PARTIAL;
|
|
} else {
|
|
result = STATE.INCORRECT;
|
|
}
|
|
}
|
|
return result;
|
|
|
|
}
|
|
|
|
// function to check correctness of reference input
|
|
const referenceChange = (e) => {
|
|
const value = e.target.value;
|
|
const string1 = String(value)
|
|
.replace(/\s+/g, "")
|
|
.toLowerCase()
|
|
.normalize("NFC");
|
|
const string2 = String(reference)
|
|
.replace(/\s+/g, "")
|
|
.toLowerCase()
|
|
.normalize("NFC");
|
|
|
|
const result = resultChecker(string1, string2);
|
|
|
|
setReference(value);
|
|
setReferenceBool(result);
|
|
};
|
|
|
|
const referenceClassName = `reference-box${
|
|
referenceBool === STATE.CORRECT ? " correct" :
|
|
referenceBool === STATE.PARTIAL ? " partial" :
|
|
" incorrect"
|
|
}`;
|
|
|
|
|
|
|
|
|
|
{/* function to check correctness of title input */}
|
|
const titleChange = (e) => {
|
|
const value = e.target.value;
|
|
let string1 = value;
|
|
let string2 = title;
|
|
string1 = String(string1)
|
|
.replace(/[\p{P}\p{S}]/gu, "") // Removes punctuation and symbols
|
|
.replace(/\s+/g, "") // Removes all whitespace
|
|
.toLowerCase()
|
|
.normalize("NFC"); // Normalizes to NFC form
|
|
|
|
string2 = String(string2)
|
|
.replace(/[\p{P}\p{S}]/gu, "")
|
|
.replace(/\s+/g, "")
|
|
.toLowerCase()
|
|
.normalize("NFC");
|
|
|
|
|
|
const result = resultChecker(string1, string2);
|
|
|
|
|
|
setTitle(value);
|
|
setTitleBool(result);
|
|
};
|
|
const titleClassName = `chapter-title-box${
|
|
titleBool=== STATE.CORRECT ? " correct" :
|
|
titleBool === STATE.PARTIAL ? " partial" :
|
|
" incorrect"
|
|
}`;
|
|
|
|
|
|
|
|
{/* function to check correctness of chapter title input */}
|
|
const chapterTitleChange = (e) => {
|
|
|
|
|
|
const value = e.target.value;
|
|
let string1 = value;
|
|
let string2 = chapterTitle;
|
|
string1 = String(string1)
|
|
.replace(/[\p{P}\p{S}]/gu, "")
|
|
.replace(/\s+/g, "")
|
|
.toLowerCase()
|
|
.normalize("NFC");
|
|
|
|
string2 = String(string2)
|
|
.replace(/[\p{P}\p{S}]/gu, "")
|
|
.replace(/\s+/g, "")
|
|
.toLowerCase()
|
|
.normalize("NFC");
|
|
|
|
const result = resultChecker(string1, string2);
|
|
|
|
setChapterTitle(value);
|
|
setChapterTitleBool(result);
|
|
};
|
|
const chapterTitleClassName = `title-box${
|
|
chapterTitleBool=== STATE.CORRECT ? " correct" :
|
|
chapterTitleBool === STATE.PARTIAL ? " partial" :
|
|
" incorrect"
|
|
}`;
|
|
|
|
|
|
// check verse input
|
|
const verseChange = (e) => {
|
|
const value = e.target.value;
|
|
let string1 = value;
|
|
let string2 = verse;
|
|
string1 = String(string1)
|
|
.replace(/[\p{P}\p{S}]/gu, "")
|
|
.replace(/\s+/g, "")
|
|
.toLowerCase()
|
|
.normalize("NFC");
|
|
string2 = String(string2)
|
|
.replace(/[\p{P}\p{S}]/gu, "")
|
|
.replace(/\s+/g, "")
|
|
.toLowerCase()
|
|
.normalize("NFC");
|
|
|
|
const result = resultChecker(string1, string2);
|
|
|
|
setVerse(value);
|
|
setVerseBool(result);
|
|
};
|
|
|
|
const verseClassName = `verse-box${
|
|
verseBool === STATE.CORRECT ? " correct" :
|
|
verseBool === STATE.PARTIAL ? " partial" :
|
|
" incorrect"
|
|
}`;
|
|
|
|
|
|
// const DiffViewer = ({oldValue, newValue}) => {
|
|
// const string1 = String(oldValue)
|
|
// .replace(/[\p{P}\p{S}]/gu, "")
|
|
// .toLowerCase()
|
|
// .normalize("NFC");
|
|
|
|
|
|
// const string2 = String(newValue)
|
|
// .replace(/[\p{P}\p{S}]/gu, "")
|
|
// .toLowerCase()
|
|
// .normalize("NFC");
|
|
|
|
// return (<StringDiff oldValue={string1} newValue={string2} diffMethod="diffWords" />)
|
|
// }
|
|
|
|
const DiffViewerStrict = ({oldValue, newValue}) => {
|
|
const string1 = String(oldValue)
|
|
.toLowerCase()
|
|
.normalize("NFC");
|
|
|
|
const string2 = String(newValue)
|
|
.toLowerCase()
|
|
.normalize("NFC");
|
|
|
|
|
|
let diffStyle = {
|
|
added: {
|
|
backgroundColor: 'var(--background-color-added)'
|
|
},
|
|
removed: {
|
|
backgroundColor: 'var(--background-color-removed)'
|
|
},
|
|
default: {}
|
|
};
|
|
|
|
|
|
return (<StringDiff
|
|
oldValue={string1}
|
|
newValue={string2}
|
|
diffMethod="diffWords"
|
|
styles={diffStyle}
|
|
/>)
|
|
}
|
|
|
|
|
|
return (
|
|
<div className="VerseValidator">
|
|
<div className="verse-number">
|
|
<h3>Verse {index}</h3>
|
|
</div>
|
|
|
|
{/* toggle hiding reference */}
|
|
{toHideReference ? (
|
|
<div>
|
|
<label className="reference-label">
|
|
{t('verse_validator.input_reference')}
|
|
</label>
|
|
<textarea
|
|
className={referenceClassName}
|
|
type="text"
|
|
id="referenceBox"
|
|
name="referenceBox"
|
|
value={inputReference}
|
|
onChange={(event) => {
|
|
|
|
if (!isComposing) {
|
|
referenceChange(event);
|
|
}
|
|
}}
|
|
/>
|
|
</div>
|
|
) : (
|
|
<h2>
|
|
{pack} - {reference}
|
|
</h2>
|
|
)}
|
|
|
|
{/* toggle chapterTitle */}
|
|
{chapterTitle && (
|
|
<div>
|
|
<label className="main-title-box-label">
|
|
{t('verse_validator.input_chapter_title')}
|
|
</label>
|
|
<textarea
|
|
className={chapterTitleClassName}
|
|
type="text"
|
|
id="chapterTitleBox"
|
|
name="chapterTitleBox"
|
|
value={inputChapterTitle}
|
|
onChange={(event) => {
|
|
if (!isComposing) {
|
|
chapterTitleChange(event);
|
|
}
|
|
}}
|
|
onCompositionStart={handleCompositionStart}
|
|
onCompositionEnd={(event) => {
|
|
setIsComposing(false);
|
|
chapterTitleChange(event);
|
|
}}
|
|
|
|
/>
|
|
</div>
|
|
)}
|
|
|
|
{/* input box for title */}
|
|
<label className="title-box-label">
|
|
{t('verse_validator.input_title')}
|
|
</label>
|
|
<textarea
|
|
className={titleClassName}
|
|
type="text"
|
|
id="titleBox"
|
|
name="titleBox"
|
|
value={inputTitle}
|
|
onChange={(event) => {
|
|
if (!isComposing) {
|
|
titleChange(event);
|
|
}
|
|
}}
|
|
onCompositionStart={handleCompositionStart}
|
|
onCompositionEnd={(event) => {
|
|
setIsComposing(false);
|
|
titleChange(event);
|
|
}}
|
|
|
|
/>
|
|
|
|
{/* input box for verse */}
|
|
<label className="verse-box-label">
|
|
{t('verse_validator.input_verse')}
|
|
</label>
|
|
<textarea
|
|
className={verseClassName}
|
|
type="text"
|
|
id="verseBox"
|
|
name="verseBox"
|
|
value={inputVerse}
|
|
onChange={(event) => {
|
|
if (!isComposing) {
|
|
verseChange(event);
|
|
}
|
|
}}
|
|
onCompositionStart={handleCompositionStart}
|
|
onCompositionEnd={(event) => {
|
|
setIsComposing(false);
|
|
verseChange(event);
|
|
}}
|
|
|
|
|
|
/>
|
|
|
|
{/* button to toggle show answer*/}
|
|
<div className="answer-button-box">
|
|
{/* <button onClick={() => setHintBool(!hintBool)}>Show Answer:</button> */}
|
|
<button onClick={() => setDiffBool(!diffBool)}>Show Answer:</button>
|
|
<button onClick={handleReset}>Reset</button>
|
|
</div>
|
|
|
|
{/* This shows the difference between given and input answers*/}
|
|
{diffBool && (
|
|
<div className="diff-box">
|
|
<h3>Differences</h3>
|
|
|
|
<p></p>
|
|
<div>
|
|
Reference:
|
|
<DiffViewerStrict
|
|
oldValue={reference}
|
|
newValue={inputReference}
|
|
/>
|
|
</div>
|
|
|
|
<p></p>
|
|
{chapterTitle && (
|
|
<div>
|
|
ChapterTitle:
|
|
<DiffViewerStrict
|
|
oldValue={chapterTitle}
|
|
newValue={inputChapterTitle}
|
|
/>
|
|
</div>
|
|
)}
|
|
|
|
<p></p>
|
|
<div>
|
|
Title:
|
|
<DiffViewerStrict
|
|
oldValue={title}
|
|
newValue={inputTitle}
|
|
/>
|
|
</div>
|
|
|
|
<p></p>
|
|
<div>
|
|
Verse:
|
|
<DiffViewerStrict
|
|
oldValue={verse}
|
|
newValue={inputVerse}
|
|
/>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
|
|
}
|
|
|
|
export default VerseValidator |