Skip to content

Commit

Permalink
feat(search-algolia): algolia externalUrl regex to navigate with wind…
Browse files Browse the repository at this point in the history
…ow.href (#5795)
  • Loading branch information
semoal authored Oct 29, 2021
1 parent 8c12983 commit adbc02e
Show file tree
Hide file tree
Showing 9 changed files with 69 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import type {
} from '@theme/NavbarItem/DefaultNavbarItem';
import IconExternalLink from '@theme/IconExternalLink';
import isInternalUrl from '@docusaurus/isInternalUrl';
import {isRegexpStringMatch} from '@docusaurus/theme-common';
import {getInfimaActiveClassName} from './index';

const dropdownLinkActiveClass = 'dropdown__link--active';
Expand Down Expand Up @@ -54,7 +55,7 @@ export function NavLink({
? {
isActive: (_match, location) =>
activeBaseRegex
? new RegExp(activeBaseRegex).test(location.pathname)
? isRegexpStringMatch(activeBaseRegex, location.pathname)
: location.pathname.startsWith(activeBaseUrl),
}
: null),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
isSamePath,
useCollapsible,
Collapsible,
isRegexpStringMatch,
useLocalPathname,
} from '@docusaurus/theme-common';
import type {
Expand All @@ -31,10 +32,7 @@ function isItemActive(
if (isSamePath(item.to, localPathname)) {
return true;
}
if (
item.activeBaseRegex &&
new RegExp(item.activeBaseRegex).test(localPathname)
) {
if (isRegexpStringMatch(item.activeBaseRegex, localPathname)) {
return true;
}
if (item.activeBasePath && localPathname.startsWith(item.activeBasePath)) {
Expand Down
2 changes: 2 additions & 0 deletions packages/docusaurus-theme-common/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,5 @@ export {
useIsomorphicLayoutEffect,
useDynamicCallback,
} from './utils/reactUtils';

export {isRegexpStringMatch} from './utils/regexpUtils';
23 changes: 23 additions & 0 deletions packages/docusaurus-theme-common/src/utils/regexpUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

/**
* Utility to convert an optional string into a Regex case sensitive and global
*/
export function isRegexpStringMatch(
regexAsString?: string,
valueToTest?: string,
): boolean {
if (
typeof regexAsString === 'undefined' ||
typeof valueToTest === 'undefined'
) {
return false;
}

return new RegExp(regexAsString, 'gi').test(valueToTest);
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,20 @@ describe('validateThemeConfig', () => {
});
});

test('externalUrlRegex config', () => {
const algolia = {
indexName: 'index',
apiKey: 'apiKey',
externalUrlRegex: 'http://external-domain.com',
};
expect(testValidateThemeConfig({algolia})).toEqual({
algolia: {
...DEFAULT_CONFIG,
...algolia,
},
});
});

test('searchParameters.facetFilters search config', () => {
const algolia = {
indexName: 'index',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {useBaseUrlUtils} from '@docusaurus/useBaseUrl';
import Link from '@docusaurus/Link';
import Head from '@docusaurus/Head';
import useSearchQuery from '@theme/hooks/useSearchQuery';
import {isRegexpStringMatch} from '@docusaurus/theme-common';
import {DocSearchButton, useDocSearchKeyboardEvents} from '@docsearch/react';
import useAlgoliaContextualFacetFilters from '@theme/hooks/useAlgoliaContextualFacetFilters';
import {translate} from '@docusaurus/Translate';
Expand All @@ -34,7 +35,7 @@ function ResultsFooter({state, onClose}) {
);
}

function DocSearch({contextualSearch, ...props}) {
function DocSearch({contextualSearch, externalUrlRegex, ...props}) {
const {siteMetadata} = useDocusaurusContext();

const contextualSearchFacetFilters = useAlgoliaContextualFacetFilters();
Expand Down Expand Up @@ -102,21 +103,28 @@ function DocSearch({contextualSearch, ...props}) {

const navigator = useRef({
navigate({itemUrl}) {
history.push(itemUrl);
// Algolia results could contain URL's from other domains which cannot
// be served through history and should navigate with window.location
if (isRegexpStringMatch(externalUrlRegex, itemUrl)) {
window.location.href = itemUrl;
} else {
history.push(itemUrl);
}
},
}).current;

const transformItems = useRef((items) => {
return items.map((item) => {
// We transform the absolute URL into a relative URL.
// Alternatively, we can use `new URL(item.url)` but it's not
// supported in IE.
const a = document.createElement('a');
a.href = item.url;
// If Algolia contains a external domain, we should navigate without relative URL
if (isRegexpStringMatch(externalUrlRegex, item.url)) {
return item;
}

// We transform the absolute URL into a relative URL.
const url = new URL(item.url);
return {
...item,
url: withBaseUrl(`${a.pathname}${a.hash}`),
url: withBaseUrl(`${url.pathname}${url.hash}`),
};
});
}).current;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';
import {
useTitleFormatter,
usePluralForm,
isRegexpStringMatch,
useDynamicCallback,
} from '@docusaurus/theme-common';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
Expand Down Expand Up @@ -121,7 +122,7 @@ function SearchPage() {
const {
siteConfig: {
themeConfig: {
algolia: {appId, apiKey, indexName},
algolia: {appId, apiKey, indexName, externalUrlRegex},
},
},
i18n: {currentLocale},
Expand Down Expand Up @@ -205,14 +206,16 @@ function SearchPage() {
_highlightResult: {hierarchy},
_snippetResult: snippet = {},
}) => {
const {pathname, hash} = new URL(url);
const parsedURL = new URL(url);
const titles = Object.keys(hierarchy).map((key) => {
return sanitizeValue(hierarchy[key].value);
});

return {
title: titles.pop(),
url: pathname + hash,
url: isRegexpStringMatch(externalUrlRegex, parsedURL.href)
? parsedURL.href
: parsedURL.pathname + parsedURL.hash,
summary: snippet.content
? `${sanitizeValue(snippet.content.value)}...`
: '',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const Schema = Joi.object({
algolia: Joi.object({
// Docusaurus attributes
contextualSearch: Joi.boolean().default(DEFAULT_CONFIG.contextualSearch),

externalUrlRegex: Joi.string().optional(),
// Algolia attributes
appId: Joi.string().default(DEFAULT_CONFIG.appId),
apiKey: Joi.string().required(),
Expand Down
3 changes: 3 additions & 0 deletions website/docs/search.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ module.exports = {
// Optional: see doc section below
contextualSearch: true,

// Optional: Specify domains where the navigation should occur through window.location instead on history.push. Useful when our Algolia config crawls multiple documentation sites and we want to navigate with window.location.href to them.
externalUrlRegex: 'external\\.com|domain\\.com',

// Optional: see doc section below
appId: 'YOUR_APP_ID',

Expand Down

0 comments on commit adbc02e

Please sign in to comment.