From 0cbbdb0b37cdc938a7598f8712fe2e299bf66f91 Mon Sep 17 00:00:00 2001 From: Maxim Zhukov Date: Fri, 12 May 2023 23:45:05 -0500 Subject: [PATCH] feat(complete-words): add complete words highlighting #8 --- package.json | 2 +- src/pages/content/components/App.tsx | 2 ++ src/pages/content/components/Highlighter.tsx | 5 ++- src/pages/content/utils/regExpHelper.tsx | 18 ++++++++++ src/pages/options/Options.tsx | 1 + src/pages/options/components/KeywordRule.tsx | 35 ++++++++++++++++++-- 6 files changed, 59 insertions(+), 4 deletions(-) create mode 100644 src/pages/content/utils/regExpHelper.tsx diff --git a/package.json b/package.json index 944aeb1..02176bf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "keywords-highlighter", - "version": "0.0.3", + "version": "0.0.4", "description": "a chrome extension that highlights keywords on web pages, making it easy to find or skip information", "license": "MIT", "repository": { diff --git a/src/pages/content/components/App.tsx b/src/pages/content/components/App.tsx index ac0b8ae..f71ae06 100644 --- a/src/pages/content/components/App.tsx +++ b/src/pages/content/components/App.tsx @@ -12,6 +12,7 @@ export default function App() { className: rule.id, keywords: rule.keywords, styles: rule.cssStyles, + highlightCompleteWords: rule.highlightCompleteWords, }; }; @@ -27,6 +28,7 @@ export default function App() { ))} diff --git a/src/pages/content/components/Highlighter.tsx b/src/pages/content/components/Highlighter.tsx index ab24d9d..28ef46f 100644 --- a/src/pages/content/components/Highlighter.tsx +++ b/src/pages/content/components/Highlighter.tsx @@ -3,21 +3,24 @@ import { findAndWrap } from "@src/lib/findAndWrapHTMLNodes"; import useMutationObservable, { DEFAULT_OPTIONS, } from "../hooks/useMutationObservable"; +import { buildFindTextRegExp } from "../utils/regExpHelper"; interface HighlighterProps { debounceTimeMs: number; keywords: string; highlightedClassName: string; + highlightCompleteWords: boolean; } export default function Highlighter({ debounceTimeMs, keywords, highlightedClassName, + highlightCompleteWords, }: HighlighterProps) { const onMutation = useCallback(() => { findAndWrap(document.body, { - findTextRegExp: new RegExp(keywords.replaceAll(",", "|"), "gi"), + findTextRegExp: buildFindTextRegExp({ keywords, highlightCompleteWords }), wrapWithTag: "span", wrapWithClassName: highlightedClassName, wrapIf: (node: Text) => { diff --git a/src/pages/content/utils/regExpHelper.tsx b/src/pages/content/utils/regExpHelper.tsx new file mode 100644 index 0000000..0ba58e1 --- /dev/null +++ b/src/pages/content/utils/regExpHelper.tsx @@ -0,0 +1,18 @@ +export function buildFindTextRegExp({ + keywords, + highlightCompleteWords, +}): RegExp { + return new RegExp( + keywords + .split(",") + .map((word: string) => { + if (highlightCompleteWords) { + return `\\b${word}\\b`; + } else { + return word; + } + }) + .join("|"), + "gi" + ); +} diff --git a/src/pages/options/Options.tsx b/src/pages/options/Options.tsx index 400421e..cda0162 100644 --- a/src/pages/options/Options.tsx +++ b/src/pages/options/Options.tsx @@ -58,6 +58,7 @@ export default function Options() { keywords: null, cssStyles: null, enabledOn: null, + highlightCompleteWords: false, }; }; diff --git a/src/pages/options/components/KeywordRule.tsx b/src/pages/options/components/KeywordRule.tsx index 85f1153..792500e 100644 --- a/src/pages/options/components/KeywordRule.tsx +++ b/src/pages/options/components/KeywordRule.tsx @@ -4,13 +4,15 @@ import TextField from "@mui/material/TextField"; import Divider from "@mui/material/Divider"; import IconButton from "@mui/material/IconButton"; import DeleteIcon from "@mui/icons-material/Delete"; -import Button from "@mui/material/Button"; +import FormControlLabel from "@mui/material/FormControlLabel"; +import Checkbox from "@mui/material/Checkbox"; export interface IKeywordRule { id: string; keywords: string; cssStyles: string; enabledOn: string; + highlightCompleteWords: boolean; } export type KeywordRuleProps = IKeywordRule & { @@ -19,7 +21,14 @@ export type KeywordRuleProps = IKeywordRule & { }; export default function KeywordRule(props: KeywordRuleProps) { - const { keywords, cssStyles, enabledOn, onRuleChange, onDeleteRule } = props; + const { + keywords, + cssStyles, + enabledOn, + highlightCompleteWords, + onRuleChange, + onDeleteRule, + } = props; const handleKeywordsChange: React.ChangeEventHandler = ( event @@ -48,6 +57,15 @@ export default function KeywordRule(props: KeywordRuleProps) { }); }; + const handleHighlightCompleteWordsChange: React.ChangeEventHandler< + HTMLInputElement + > = (event) => { + onRuleChange({ + ...props, + highlightCompleteWords: event.target.checked, + }); + }; + const handleDeleteClick = () => { onDeleteRule({ ...props, @@ -103,6 +121,19 @@ export default function KeywordRule(props: KeywordRuleProps) { /> + + + } + label="Only highlight complete words" + /> + +