From 8975e57306240541009a5ceb8382c6ce0cbe5e98 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Mon, 15 Jul 2024 14:51:09 -0400 Subject: [PATCH] [GlossWithSuggestions] Use ... for all but last word (#3226) --- .../GlossWithSuggestions.tsx | 3 ++- src/utilities/spellChecker.ts | 15 ++++++++++- src/utilities/tests/spellChecker.test.ts | 26 +++++++++++++++++++ 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/components/DataEntry/DataEntryTable/EntryCellComponents/GlossWithSuggestions.tsx b/src/components/DataEntry/DataEntryTable/EntryCellComponents/GlossWithSuggestions.tsx index eb79e61399..f4db3e58e1 100644 --- a/src/components/DataEntry/DataEntryTable/EntryCellComponents/GlossWithSuggestions.tsx +++ b/src/components/DataEntry/DataEntryTable/EntryCellComponents/GlossWithSuggestions.tsx @@ -10,6 +10,7 @@ import { Key } from "ts-key-enum"; import { type WritingSystem } from "api/models"; import { LiWithFont, TextFieldWithFont } from "utilities/fontComponents"; +import SpellChecker from "utilities/spellChecker"; import SpellCheckerContext from "utilities/spellCheckerContext"; interface GlossWithSuggestionsProps { @@ -84,7 +85,7 @@ export default function GlossWithSuggestions( aria-selected={selected} lang={props.analysisLang.bcp47} > - {option} + {SpellChecker.replaceAllButLastWordWithEllipses(option)} )} onKeyPress={(e: KeyboardEvent) => { diff --git a/src/utilities/spellChecker.ts b/src/utilities/spellChecker.ts index e938ae1529..847a86854c 100644 --- a/src/utilities/spellChecker.ts +++ b/src/utilities/spellChecker.ts @@ -70,8 +70,9 @@ export default class SpellChecker { }); } + /** Trim whitespace from the start and non-letter/-mark/-number characters from the end, + * then split off the final word. */ static cleanAndSplit(word: string): SplitWord { - // Trim whitespace from the start and non-letter/-mark/-number characters from the end. // Use of \p{L}\p{M}\p{N} here matches that in split_dictionary.py. // Cf. https://en.wikipedia.org/wiki/Unicode_character_property word = word.trimStart().replace(/[^\p{L}\p{M}\p{N}]*$/u, ""); @@ -89,6 +90,18 @@ export default class SpellChecker { return { allButFinal, final }; } + /** If the given string, split by separator (non-letter/-mark/-number) characters, + * is multiple words, replace all but the last word with ellipses (...). + * (Assumes all end-of-string separator characters have been removed, + * which is the case for suggestions from this SpellChecker.) */ + public static replaceAllButLastWordWithEllipses(word: string): string { + // Split by non-letter/-mark/-number characters + const words = word.split(/[^\p{L}\p{M}\p{N}]/u).filter((w) => w); + // Find the last non-letter/-mark/-number character + const finalSep = word.match(/[^\p{L}\p{M}\p{N}]/gu)?.pop(); + return words.length > 1 ? `...${finalSep}${words[words.length - 1]}` : word; + } + // If the word string is multiple words, separate and // find spelling suggestions for the last word. getSpellingSuggestions(word: string): string[] { diff --git a/src/utilities/tests/spellChecker.test.ts b/src/utilities/tests/spellChecker.test.ts index 009c291c92..f208c1a6fc 100644 --- a/src/utilities/tests/spellChecker.test.ts +++ b/src/utilities/tests/spellChecker.test.ts @@ -114,4 +114,30 @@ describe("SpellChecker", () => { }, 500); }); }); + + describe("replaceAllButLastWordWithEllipses", () => { + it("handles empty string", () => { + expect(SpellChecker.replaceAllButLastWordWithEllipses("")).toEqual(""); + }); + + it("does nothing if only 1 word", () => { + const word = " *(- #/;-something"; + const result = SpellChecker.replaceAllButLastWordWithEllipses(word); + expect(result).toEqual(word); + }); + + it("replaces with ellipses when multiple words", () => { + expect( + SpellChecker.replaceAllButLastWordWithEllipses("double-word") + ).toEqual("...-word"); + + expect( + SpellChecker.replaceAllButLastWordWithEllipses("now 3 words") + ).toEqual("... words"); + + expect( + SpellChecker.replaceAllButLastWordWithEllipses("paren before (end") + ).toEqual("...(end"); + }); + }); });