docs: fix search character escaping
This commit is contained in:
parent
bb0b709b48
commit
27b6112cba
@ -72,6 +72,10 @@ const StyledSuggestionSection = styled('div')`
|
|||||||
gap: 4px;
|
gap: 4px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
function escapeRegExp(str: string) {
|
||||||
|
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
|
||||||
|
}
|
||||||
|
|
||||||
interface SearchModalProps {
|
interface SearchModalProps {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
@ -102,106 +106,104 @@ const SearchModal: FC<SearchModalProps> = ({ open, onClose, searchablePages }) =
|
|||||||
|
|
||||||
const searchResults = useSearchScores(search, searchablePages);
|
const searchResults = useSearchScores(search, searchablePages);
|
||||||
|
|
||||||
const renderedResults = useMemo(
|
const renderedResults = useMemo(() => {
|
||||||
() =>
|
const escapedSearch = escapeRegExp(search);
|
||||||
searchResults?.length > 0 ? (
|
|
||||||
[...Array<unknown>(SEARCH_RESULTS_TO_SHOW)].map((_, index) => {
|
|
||||||
if (searchResults.length <= index) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = searchResults[index];
|
return searchResults?.length > 0 ? (
|
||||||
const { entry } = result;
|
[...Array<unknown>(SEARCH_RESULTS_TO_SHOW)].map((_, index) => {
|
||||||
let summary = entry.textContent;
|
if (searchResults.length <= index) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!result.isExactTitleMatch) {
|
const result = searchResults[index];
|
||||||
|
const { entry } = result;
|
||||||
|
let summary = entry.textContent;
|
||||||
|
|
||||||
|
if (!result.isExactTitleMatch) {
|
||||||
|
const match = new RegExp(
|
||||||
|
`(?:[\\s]+[^\\s]+){0,10}[\\s]*${escapeRegExp(
|
||||||
|
escapedSearch,
|
||||||
|
)}(?![^<>]*(([/"']|]]|\\b)>))[\\s]*(?:[^\\s]+\\s){0,25}`,
|
||||||
|
'ig',
|
||||||
|
).exec(entry.textContent);
|
||||||
|
if (match && match.length >= 1) {
|
||||||
|
summary = `...${match[0].trim()}...`;
|
||||||
|
} else {
|
||||||
const match = new RegExp(
|
const match = new RegExp(
|
||||||
`(?:[\\s]+[^\\s]+){0,10}[\\s]*${search}(?![^<>]*(([/"']|]]|\\b)>))[\\s]*(?:[^\\s]+\\s){0,25}`,
|
`(?:[\\s]+[^\\s]+){0,10}[\\s]*(${escapedSearch
|
||||||
|
.split(' ')
|
||||||
|
.join('|')})(?![^<>]*(([/"']|]]|\\b)>))[\\s]*(?:[^\\s]+\\s){0,25}`,
|
||||||
'ig',
|
'ig',
|
||||||
).exec(entry.textContent);
|
).exec(entry.textContent);
|
||||||
if (match && match.length >= 1) {
|
if (match && match.length >= 1) {
|
||||||
summary = `...${match[0].trim()}...`;
|
summary = `...${match[0].trim()}...`;
|
||||||
} else {
|
|
||||||
const match = new RegExp(
|
|
||||||
`(?:[\\s]+[^\\s]+){0,10}[\\s]*(${search
|
|
||||||
.split(' ')
|
|
||||||
.join('|')})(?![^<>]*(([/"']|]]|\\b)>))[\\s]*(?:[^\\s]+\\s){0,25}`,
|
|
||||||
'ig',
|
|
||||||
).exec(entry.textContent);
|
|
||||||
if (match && match.length >= 1) {
|
|
||||||
summary = `...${match[0].trim()}...`;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
summary = summary?.replace(
|
summary = summary?.replace(
|
||||||
new RegExp(`(${search.split(' ').join('|')})(?![^<>]*(([/"']|]]|\\b)>))`, 'ig'),
|
new RegExp(`(${escapedSearch.split(' ').join('|')})(?![^<>]*(([/"']|]]|\\b)>))`, 'ig'),
|
||||||
`<strong style="color: ${theme.palette.primary.main}">$1</strong>`,
|
`<strong style="color: ${theme.palette.primary.main}">$1</strong>`,
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SearchResult
|
<SearchResult
|
||||||
key={`result-${entry.url}`}
|
key={`result-${entry.url}`}
|
||||||
entry={entry}
|
entry={entry}
|
||||||
summary={summary}
|
summary={summary}
|
||||||
onClick={handleClose}
|
onClick={handleClose}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
) : isNotEmpty(search) ? (
|
) : isNotEmpty(escapedSearch) ? (
|
||||||
<Typography
|
<Typography
|
||||||
variant="h3"
|
variant="h3"
|
||||||
component="div"
|
component="div"
|
||||||
key="no-results"
|
key="no-results"
|
||||||
sx={{ width: '100%', textAlign: 'center', marginTop: '16px' }}
|
sx={{ width: '100%', textAlign: 'center', marginTop: '16px' }}
|
||||||
>
|
>
|
||||||
No results found
|
No results found
|
||||||
</Typography>
|
</Typography>
|
||||||
) : (
|
) : (
|
||||||
<StyledSuggestions>
|
<StyledSuggestions>
|
||||||
<StyledSuggestionSection>
|
<StyledSuggestionSection>
|
||||||
<Typography variant="h3" sx={{ marginBottom: '4px' }}>
|
<Typography variant="h3" sx={{ marginBottom: '4px' }}>
|
||||||
Getting Started
|
Getting Started
|
||||||
</Typography>
|
</Typography>
|
||||||
<SuggestionLink href="/docs/start-with-a-template">
|
<SuggestionLink href="/docs/start-with-a-template">Start With a Template</SuggestionLink>
|
||||||
Start With a Template
|
<SuggestionLink href="/docs/add-to-your-site">Add to Your Site</SuggestionLink>
|
||||||
</SuggestionLink>
|
<SuggestionLink href="/docs/configuration-options">Configuration Options</SuggestionLink>
|
||||||
<SuggestionLink href="/docs/add-to-your-site">Add to Your Site</SuggestionLink>
|
<SuggestionLink href="/docs/collection-overview">Collections</SuggestionLink>
|
||||||
<SuggestionLink href="/docs/configuration-options">
|
</StyledSuggestionSection>
|
||||||
Configuration Options
|
<StyledSuggestionSection>
|
||||||
</SuggestionLink>
|
<Typography variant="h3" sx={{ marginBottom: '4px' }}>
|
||||||
<SuggestionLink href="/docs/collection-overview">Collections</SuggestionLink>
|
Backends
|
||||||
</StyledSuggestionSection>
|
</Typography>
|
||||||
<StyledSuggestionSection>
|
<SuggestionLink href="/docs/github-backend">GitHub</SuggestionLink>
|
||||||
<Typography variant="h3" sx={{ marginBottom: '4px' }}>
|
<SuggestionLink href="/docs/bitbucket-backend">Bitbucket</SuggestionLink>
|
||||||
Backends
|
<SuggestionLink href="/docs/gitlab-backend">GitLab</SuggestionLink>
|
||||||
</Typography>
|
</StyledSuggestionSection>
|
||||||
<SuggestionLink href="/docs/github-backend">GitHub</SuggestionLink>
|
<StyledSuggestionSection>
|
||||||
<SuggestionLink href="/docs/bitbucket-backend">Bitbucket</SuggestionLink>
|
<Typography variant="h3" sx={{ marginBottom: '4px' }}>
|
||||||
<SuggestionLink href="/docs/gitlab-backend">GitLab</SuggestionLink>
|
Customize Your CMS
|
||||||
</StyledSuggestionSection>
|
</Typography>
|
||||||
<StyledSuggestionSection>
|
<SuggestionLink href="/docs/custom-previews">Custom Previews</SuggestionLink>
|
||||||
<Typography variant="h3" sx={{ marginBottom: '4px' }}>
|
<SuggestionLink href="/docs/custom-widgets">Custom Widgets</SuggestionLink>
|
||||||
Customize Your CMS
|
<SuggestionLink href="/docs/custom-icons">Custom Icons</SuggestionLink>
|
||||||
</Typography>
|
<SuggestionLink href="/docs/additional-links">Custom Pages / Links</SuggestionLink>
|
||||||
<SuggestionLink href="/docs/custom-previews">Custom Previews</SuggestionLink>
|
</StyledSuggestionSection>
|
||||||
<SuggestionLink href="/docs/custom-widgets">Custom Widgets</SuggestionLink>
|
<StyledSuggestionSection>
|
||||||
<SuggestionLink href="/docs/custom-icons">Custom Icons</SuggestionLink>
|
<Typography variant="h3" sx={{ marginBottom: '4px' }}>
|
||||||
<SuggestionLink href="/docs/additional-links">Custom Pages / Links</SuggestionLink>
|
Widgets
|
||||||
</StyledSuggestionSection>
|
</Typography>
|
||||||
<StyledSuggestionSection>
|
<SuggestionLink href="/docs/widget-string">String</SuggestionLink>
|
||||||
<Typography variant="h3" sx={{ marginBottom: '4px' }}>
|
<SuggestionLink href="/docs/widget-image">Image</SuggestionLink>
|
||||||
Widgets
|
<SuggestionLink href="/docs/widget-datetime">Datetime</SuggestionLink>
|
||||||
</Typography>
|
<SuggestionLink href="/docs/widget-markdown">Markdown</SuggestionLink>
|
||||||
<SuggestionLink href="/docs/widget-string">String</SuggestionLink>
|
</StyledSuggestionSection>
|
||||||
<SuggestionLink href="/docs/widget-image">Image</SuggestionLink>
|
</StyledSuggestions>
|
||||||
<SuggestionLink href="/docs/widget-datetime">Datetime</SuggestionLink>
|
);
|
||||||
<SuggestionLink href="/docs/widget-markdown">Markdown</SuggestionLink>
|
}, [handleClose, search, searchResults, theme.palette.primary.main]);
|
||||||
</StyledSuggestionSection>
|
|
||||||
</StyledSuggestions>
|
|
||||||
),
|
|
||||||
[handleClose, search, searchResults, theme.palette.primary.main],
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledDialog open={open} onClose={handleClose} fullScreen={fullScreen} fullWidth>
|
<StyledDialog open={open} onClose={handleClose} fullScreen={fullScreen} fullWidth>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user