content/frontend/search/search_helpers.js (87 lines of code) (raw):

/** * Shared functions for Lunr and Google search. */ /** * Check URL parameters for search parameters. * * We support "q" for the query string as it's a Google standard, * and also "query" as it has been long-documented in the * GitLab handbook as a Docs search parameter. * * See https://about.gitlab.com/handbook/tools-and-tips/searching/ * * @returns * An object containing query parameters. */ export const getSearchParamsFromURL = () => { const searchParams = new URLSearchParams(window.location.search); return { qParam: searchParams.get('q') || searchParams.get('query') || '', pageParam: searchParams.get('page') || '', filterParam: searchParams.get('filters') || '', }; }; /** * Update URL parameters. * * This allows users to retrace their steps after a search. * * @param params Object * Key/value pairs with the param name and value. * Values can be strings or arrays. */ export const updateURLParams = (params) => { const queryString = Object.entries(params) .filter(([, value]) => value !== '' && !(Array.isArray(value) && value.length === 0)) .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`) .join('&'); window.history.pushState(null, '', `${window.location.pathname}?${queryString}`); }; /** * Search filters. * * Option properties: * - text: Used for checkbox labels * - value: References values in the "docs-site-section" metatag, which is included each search result. * - id: Machine-friendly version of the text, used for analytics and URL params. */ export const SEARCH_FILTERS = [ { title: 'Filter by', options: [ { text: 'Tutorials', value: 'tutorials', id: 'tutorials', }, { text: 'Installation docs', value: 'install,subscribe', id: 'install', }, { text: 'Administration docs', value: 'administer,subscribe', id: 'administer', }, { text: 'User docs', value: 'subscribe,use_gitlab,gitlab_duo', id: 'user', }, { text: 'Extension and API docs', value: 'extend', id: 'extend', }, { text: 'Contributor docs', value: 'contribute', id: 'contribute', }, { text: 'Solution docs', value: 'solutions', id: 'solutions', }, ], }, ]; /** * Convert between filter values and filter IDs. * * @param Array arr * Selected filters to convert. * @param Boolean isToID * true to convert to IDs, false to convert to values * * @returns Array */ export const convertFilterValues = (arr, isToID) => { const convertedArr = arr.map((item) => { for (const filter of SEARCH_FILTERS) { for (const option of filter.options) { if ((isToID && option.value === item) || (!isToID && option.id === item)) { return isToID ? option.id : option.value; } } } return null; }); return convertedArr.filter((item) => item !== null); }; /** * Keyboard shortcuts. */ export const activateKeyboardShortcut = () => { document.addEventListener('keydown', (e) => { // Focus on the search form with the forward slash and S keys. const shortcutKeys = ['/', 's']; if (!shortcutKeys.includes(e.key) || e.ctrlKey || e.metaKey) return; if (/^(?:input|textarea|select|button)$/i.test(e.target.tagName)) return; e.preventDefault(); document.querySelector('input[type="search"]').focus(); }); }; /** * Remove formatting and boilerplate text from a page title * * We use this when we want to reference the title of a page, * without any extra formatting. */ export const cleanTitle = (htmlTitle) => { return ( htmlTitle // Remove any text that starts with " | " .replace(/\s*\|.*$/, '') // Some pages use backticks to style words in titles as code. // We don't want to include these in places where we aren't parsing markdown .replaceAll('`', '') .trim() ); };