From 26b23d879b3c07cffdb86f87177401a5d200f15b Mon Sep 17 00:00:00 2001 From: Inga Date: Sun, 14 Jan 2024 19:22:11 +0000 Subject: [PATCH] implemented spellchecker --- src/spellChecker/errorsDisplay.css | 8 ++++ src/spellChecker/errorsDisplay.tsx | 70 ++++++++++++++++++++++++++++ src/spellChecker/index.tsx | 74 +++++++++++++++++++++++++++--- src/spellChecker/types.ts | 4 ++ src/style.css | 1 - 5 files changed, 150 insertions(+), 7 deletions(-) create mode 100644 src/spellChecker/errorsDisplay.css create mode 100644 src/spellChecker/errorsDisplay.tsx create mode 100644 src/spellChecker/types.ts diff --git a/src/spellChecker/errorsDisplay.css b/src/spellChecker/errorsDisplay.css new file mode 100644 index 0000000..79ece07 --- /dev/null +++ b/src/spellChecker/errorsDisplay.css @@ -0,0 +1,8 @@ +.validated-text { + white-space: pre-line; +} + +.fragment-incorrect { + font-weight: bold; + color: red; +} \ No newline at end of file diff --git a/src/spellChecker/errorsDisplay.tsx b/src/spellChecker/errorsDisplay.tsx new file mode 100644 index 0000000..9f160d1 --- /dev/null +++ b/src/spellChecker/errorsDisplay.tsx @@ -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

No errors!

; + } + + const chunks = toChunks({ originalText, spellcheckErrors }); + + return ( +

+ {chunks.map((chunk) => ( + + {chunk.text} + + ))} +

+ ); +}; diff --git a/src/spellChecker/index.tsx b/src/spellChecker/index.tsx index 5c91954..6a1b7e7 100644 --- a/src/spellChecker/index.tsx +++ b/src/spellChecker/index.tsx @@ -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(); + const [regex, setRegex] = useState(); + const [errorsDisplayParams, setErrorsDisplayParams] = + useState({ + 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 = 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 (
- +
+