implemented spellchecker

main
Inga 🏳‍🌈 12 months ago
parent dccbf7cde8
commit 26b23d879b
  1. 8
      src/spellChecker/errorsDisplay.css
  2. 70
      src/spellChecker/errorsDisplay.tsx
  3. 74
      src/spellChecker/index.tsx
  4. 4
      src/spellChecker/types.ts
  5. 1
      src/style.css

@ -0,0 +1,8 @@
.validated-text {
white-space: pre-line;
}
.fragment-incorrect {
font-weight: bold;
color: red;
}

@ -0,0 +1,70 @@
import './errorsDisplay.css';
export type ErrorsDisplayParams = {
originalText: string;
spellcheckErrors: {
start: number;
end: number;
}[];
};
type TextChunk = {
text: string;
index: number;
isCorrect: boolean;
};
const toChunks = ({ originalText, spellcheckErrors }: ErrorsDisplayParams) => {
const chunks: TextChunk[] = [];
let lastIndex = 0;
for (const error of spellcheckErrors) {
chunks.push({
text: originalText.slice(lastIndex, error.start),
index: lastIndex,
isCorrect: true,
});
chunks.push({
text: originalText.slice(error.start, error.end),
index: error.start,
isCorrect: false,
});
lastIndex = error.end;
}
chunks.push({
text: originalText.slice(lastIndex, originalText.length),
index: lastIndex,
isCorrect: true,
});
return chunks.filter(({ text }) => !!text.length);
};
export const ErrorsDisplay = ({
originalText,
spellcheckErrors,
}: ErrorsDisplayParams) => {
if (!spellcheckErrors.length) {
return <p>No errors!</p>;
}
const chunks = toChunks({ originalText, spellcheckErrors });
return (
<p class="validated-text">
{chunks.map((chunk) => (
<span
key={chunk.index}
class={
chunk.isCorrect
? 'fragment-correct'
: 'fragment-incorrect'
}
>
{chunk.text}
</span>
))}
</p>
);
};

@ -1,17 +1,79 @@
import { useEffect, useState } from 'preact/hooks';
import { useCallback, useEffect, useState } from 'preact/hooks';
import type { JSX } from 'preact/jsx-runtime';
import { ErrorsDisplay, ErrorsDisplayParams } from './errorsDisplay';
export const SpellChecker = () => {
const [regex, setRegex] = useState<string>();
const [regex, setRegex] = useState<RegExp>();
const [errorsDisplayParams, setErrorsDisplayParams] =
useState<ErrorsDisplayParams>({
originalText: '',
spellcheckErrors: [],
});
useEffect(() => {
if (!regex) {
setRegex(new URL(`./assets/img/abc.def`, import.meta.url).href);
window
.fetch(
new URL(
`./assets/th-en-x-basic.ooo-thesaurus`,
import.meta.url,
).href,
)
.then((response) => response.text())
.then((regexString) => {
console.time('regex-parse');
setRegex(new RegExp(regexString, 'gi'));
console.timeEnd('regex-parse');
})
.catch((err) => console.error(err));
}
}, [regex]);
const handleSubmit: JSX.GenericEventHandler<HTMLFormElement> = useCallback(
(e) => {
e.preventDefault();
if (!regex) {
return;
}
const formData = new FormData(e.currentTarget);
const originalText = formData.get('text')?.toString() ?? '';
console.time('regex-execute');
const results = [...originalText.matchAll(regex)];
console.timeEnd('regex-execute');
const spellcheckErrors = results.map((result) => {
const start = result.index;
if (start === undefined) {
throw new Error('Should not happen for non-empty results');
}
return {
start,
end: start + result[0].length,
};
});
setErrorsDisplayParams({
originalText,
spellcheckErrors,
});
},
[regex],
);
return (
<section>
<textarea rows={10} cols={100}>
{regex}
</textarea>
<form onSubmit={handleSubmit}>
<textarea rows={10} cols={100} name="text" />
<br />
<button type="submit" disabled={!regex}>
Validate
</button>
</form>
<ErrorsDisplay {...errorsDisplayParams} />
</section>
);
};

@ -0,0 +1,4 @@
export type SpellcheckError = {
start: number;
end: number;
};

@ -19,7 +19,6 @@ body {
#app {
max-width: 1280px;
margin: 0 auto;
text-align: center;
}
img {

Loading…
Cancel
Save