Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
679669a
adding spell checker as an enabled mode
satti-hari-krishna-reddy Jun 16, 2024
896a77e
specifying path to spell checker
satti-hari-krishna-reddy Jun 16, 2024
a6958e2
included spell checker as a new mode
satti-hari-krishna-reddy Jun 16, 2024
12eb793
adding spell check as a link in the nav bar
satti-hari-krishna-reddy Jun 16, 2024
0138309
empty initial spell check component
satti-hari-krishna-reddy Jun 17, 2024
03ee1b5
fixing import for spell check component
satti-hari-krishna-reddy Jun 17, 2024
530cd5b
initial code for spell checker interface
satti-hari-krishna-reddy Jun 17, 2024
46ca008
fix issues with text rendering
satti-hari-krishna-reddy Jun 21, 2024
b35ca82
fixng styling
satti-hari-krishna-reddy Jun 21, 2024
45855bb
fixing issue with state updates with renderHighlightText
satti-hari-krishna-reddy Jun 22, 2024
f91abdd
adding handleSubmit function
satti-hari-krishna-reddy Jun 22, 2024
7c21473
refactoring SpellCheck component
satti-hari-krishna-reddy Jun 22, 2024
61fb332
removing unnecessary script
satti-hari-krishna-reddy Jun 22, 2024
554f455
trying to fix eslint issues
satti-hari-krishna-reddy Jun 28, 2024
30a2847
fixed lint errors
satti-hari-krishna-reddy Jun 28, 2024
1dae8d2
fixed a failing test case
satti-hari-krishna-reddy Jun 28, 2024
52d2efe
Merge branch 'apertium:master' into gsoc-speller-checker
satti-hari-krishna-reddy Jun 28, 2024
23b4597
fixing the text not showing up from local storage
satti-hari-krishna-reddy Jun 28, 2024
5587092
fixing prettier error and improving applySuggestion function
satti-hari-krishna-reddy Jun 28, 2024
bd0e486
saving and restoring caret position
satti-hari-krishna-reddy Jun 29, 2024
5940fae
getting available voikko modes
satti-hari-krishna-reddy Jul 26, 2024
67971dc
making sure to strip way any html tags
satti-hari-krishna-reddy Jul 26, 2024
ad0fdb1
renaming the apy endpoint for spell checking
satti-hari-krishna-reddy Jul 28, 2024
bf50986
test(SpellChecker): add initial unit test cases
satti-hari-krishna-reddy Jul 28, 2024
33877f0
reverting to spellers
satti-hari-krishna-reddy Jul 29, 2024
5269f1f
fix small circle issue when no suggestions are returned
satti-hari-krishna-reddy Aug 1, 2024
34a4554
Added logic for instant spell check triggered after a delay of 3 seco…
satti-hari-krishna-reddy Aug 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
fixng styling
  • Loading branch information
satti-hari-krishna-reddy committed Jun 21, 2024
commit b35ca825433022fc9aca0c4efdf7bc177cc7eeaf
144 changes: 82 additions & 62 deletions src/components/spellchecker/SpellChecker.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as React from 'react';
import React, { useState, useRef, useEffect } from 'react';
import Button from 'react-bootstrap/Button';
import Col from 'react-bootstrap/Col';
import Form from 'react-bootstrap/Form';
Expand All @@ -25,27 +25,11 @@ const SpellChecker = (): React.ReactElement => {
const history = useHistory();
const { t, tLang } = useLocalization();
const { trackEvent } = useMatomo();
const [suggestions, setSuggestions] = React.useState<Suggestion[]>([
{
token: 'Thiss',
known: false,
sugg: [
['This', 0.9],
['Thus', 0.1],
],
},
{
token: 'exampel',
known: false,
sugg: [
['example', 0.95],
['exemplar', 0.05],
],
},
]);
const [selectedWord, setSelectedWord] = React.useState<string | null>(null);
const [loading, setLoading] = React.useState<boolean>(false);
const [error, setError] = React.useState<Error | null>(null);
const [suggestions, setSuggestions] = useState<Suggestion[]>([]);
const [selectedWord, setSelectedWord] = useState<string | null>(null);
const [loading, setLoading] = useState<boolean>(false);
const [error, setError] = useState<Error | null>(null);
const [suggestionPosition, setSuggestionPosition] = useState<{ top: number, left: number } | null>(null);

const [lang, setLang] = useLocalStorage('spellerLang', Object.keys(Spellers)[0], {
overrideValue: toAlpha3Code(getUrlParam(history.location.search, langUrlParam)),
Expand All @@ -56,65 +40,99 @@ const SpellChecker = (): React.ReactElement => {
overrideValue: getUrlParam(history.location.search, textUrlParam),
});

React.useEffect(() => {
useEffect(() => {
let search = buildNewSearch({ [langUrlParam]: lang, [textUrlParam]: text });
if (search.length > MaxURLLength) {
search = buildNewSearch({ [langUrlParam]: lang });
}
history.replace({ search });
}, [history, lang, text]);

const spellcheckRef = React.useRef<HTMLDivElement | null>(null);
const spellcheckRef = useRef<HTMLDivElement | null>(null);

const handleSubmit = () => {
if (text.trim().length === 0) {
return;
}

// Simulating the API call
setLoading(true);
setTimeout(() => {
setSuggestions(checkSpelling(text));
setError(null);
setLoading(false);
}, 1000);
};

const handleInput = (e: React.FormEvent<HTMLDivElement>) => {
setText(e.currentTarget.innerText);
};

const handleWordClick = (word: string) => {
console.log("Word clicked:", word);
const handleWordClick = (word: string, event: React.MouseEvent) => {
setSelectedWord(word);
const rect = event.currentTarget.getBoundingClientRect();
setSuggestionPosition({
top: rect.bottom + window.scrollY + 3, // Adjust for scrolling
left: rect.left + window.scrollX -2,
});
};

const applySuggestion = (suggestion: string) => {
if (!selectedWord) return;

const updatedText = text.replace(new RegExp(`\\b${selectedWord}\\b`, 'g'), suggestion);
setText(updatedText); // Schedule state update

console.log(text)
setText(updatedText);
setSelectedWord(null);
renderHighlightedText()

// Remove the applied suggestion from the suggestions list
setSuggestions((prevSuggestions) =>
prevSuggestions.filter((s) => s.token !== selectedWord)
);
};

const renderHighlightedText = () => {
if (text.trim().length === 0) {
return;
}
console.log(text)
console.log("yo i got called!!!")

const contentElement = spellcheckRef.current;
if (contentElement instanceof HTMLElement) {

const parts = text.split(/(\s+)/).map((word, index) => {
const suggestion = suggestions.find((s) => s.token === word && !s.known);
if (suggestion) {
return `<span key=${index} class="misspelled">${word}</span>`;
} else {
return `<span key=${index} class="correct">${word}</span>`;
}
}).join('');

contentElement.innerHTML = parts;

const misspelledElements = contentElement.querySelectorAll('.misspelled');
misspelledElements.forEach((element, index) => {
const word = element.textContent || '';
element.addEventListener('click', () => handleWordClick(word));
});
}
const checkSpelling = (inputText: string): Suggestion[] => {
// Simulated response from the spell checker
return [
{
token: 'Thiss',
known: false,
sugg: [
['This', 0.9],
['Thus', 0.1],
['Thus', 0.1],
['Thus', 0.1],
['Thus', 0.1],
['Thus', 0.1],
['Thus', 0.1],
['Thus', 0.1],
['Thus', 0.1],
],
},
{
token: 'exampel',
known: false,
sugg: [
['example', 0.95],
['exemplar', 0.05],
],
},
];
};

const renderHighlightedText = () => {
const parts = text.split(/(\s+)/).map((word, index) => {
const suggestion = suggestions.find((s) => s.token === word && !s.known);
if (suggestion) {
return (
<span key={index} className="misspelled" onClick={(e) => handleWordClick(word, e)}>
{word}
</span>
);
}
return word;
});
return <>{parts}</>;
}

return (
<Form aria-label="Spell Checker" onSubmit={(event) => event.preventDefault()}>
<Form.Group className="row" controlId="speller-lang">
Expand Down Expand Up @@ -142,18 +160,20 @@ const SpellChecker = (): React.ReactElement => {
contentEditable
ref={spellcheckRef}
onInput={handleInput}
/>
>
{renderHighlightedText()}
</div>
</Col>
</Form.Group>
<Form.Group className="row">
<Col className="offset-md-2 col-md-10 offset-lg-1" md="10">
<Button onClick={renderHighlightedText} type="submit" variant="primary">
<Button onClick={handleSubmit} type="submit" variant="primary">
{t('Check')}
</Button>
</Col>
</Form.Group>
{selectedWord && (
<div className="suggestions">
{selectedWord && suggestionPosition && (
<div className="suggestions" style={{ top: suggestionPosition.top, left: suggestionPosition.left }}>
{suggestions
.find((s) => s.token === selectedWord)
?.sugg.map(([sugg, _], index) => (
Expand Down
82 changes: 35 additions & 47 deletions src/components/spellchecker/spellchecker.css
Original file line number Diff line number Diff line change
@@ -1,49 +1,37 @@
.content-editable {
border: 1px solid #ccc;
padding: 10px;
min-height: 150px;
white-space: pre-wrap;
word-wrap: break-word;
}

.misspelled {
position: relative;
display: inline-block;
text-decoration: underline wavy red;
cursor: pointer;
}

.suggestions {
background: white;
border: 1px solid #ccc;
max-height: 150px;
overflow-y: auto;
text-align: center;
border-radius: 6px;
padding: 5px 0;
position: absolute;
z-index: 1;
top: 150%;
left: 50%;
margin-left: -60px;
}
.suggestions::after {
content: "";
position: absolute;
bottom: 100%;
left: 50%;
margin-left: -5px;
border-width: 5px;
border-style: solid;
border-color: transparent transparent black transparent;
}
border: 1px solid #ccc;
padding: 10px;
min-height: 150px;
white-space: pre-wrap;
word-wrap: break-word;
}

.suggestions div {
padding: 5px;
cursor: pointer;
}

.suggestions div:hover {
background-color: #f0f0f0;
}

.misspelled {
text-decoration: underline wavy red;
cursor: pointer;
}

.suggestions {
text-align: center;
position: absolute;
background: white;
border: 1px solid #ccc;
z-index: 1000;
max-height: 150px;
overflow-y: auto;
white-space: nowrap;
width: auto; /* Adjusted width */
padding: 5px;
border-radius: 6px;
box-shadow: 0px 0px 10px rgba(0,0,0,0.1); /* Optional: for a slight shadow */
;
}

.suggestions div {
padding: 5px;
cursor: pointer;
}

.suggestions div:hover {
background-color: #f0f0f0;
}