114 lines
3 KiB
JavaScript
114 lines
3 KiB
JavaScript
// TODO: We should really be using the xss package by installing it in package.json
|
|
// but for now filterXSS is global because of legacy JS
|
|
|
|
import { request } from '../http';
|
|
|
|
function getParameterByName(name, url = window.location.href) {
|
|
const sanitizedName = name.replace(/[[\]]/g, '\\$&');
|
|
const regex = new RegExp(`[?&]${sanitizedName}(=([^&#]*)|&|#|$)`);
|
|
const results = regex.exec(url);
|
|
|
|
if (!results) {
|
|
return null;
|
|
}
|
|
|
|
if (!results[2]) {
|
|
return '';
|
|
}
|
|
|
|
return decodeURIComponent(results[2].replace(/\+/g, ' '));
|
|
}
|
|
|
|
function getFilterParameters(url) {
|
|
const filters = getParameterByName('filters', url);
|
|
|
|
if (filters) {
|
|
return `&filters=${filters}`;
|
|
}
|
|
|
|
return '';
|
|
}
|
|
|
|
export const hasInstantClick = () => typeof instantClick !== 'undefined';
|
|
|
|
function fixedEncodeURIComponent(str) {
|
|
// from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent
|
|
return encodeURIComponent(str).replace(
|
|
/[!'()*]/g,
|
|
(c) => `%${c.charCodeAt(0).toString(16)}`,
|
|
);
|
|
}
|
|
|
|
export function displaySearchResults({
|
|
searchTerm,
|
|
location = window.location,
|
|
}) {
|
|
const baseUrl = location.origin;
|
|
const sanitizedQuery = fixedEncodeURIComponent(searchTerm);
|
|
const filterParameters = getFilterParameters(location.href);
|
|
|
|
InstantClick.display(
|
|
`${baseUrl}/search?q=${sanitizedQuery}${filterParameters}`,
|
|
);
|
|
}
|
|
|
|
export function getInitialSearchTerm(querystring) {
|
|
const matches = /(?:&|\?)?q=([^&=]+)/.exec(querystring);
|
|
const rawSearchTerm =
|
|
matches !== null && matches.length === 2
|
|
? decodeURIComponent(matches[1].replace(/\+/g, '%20'))
|
|
: '';
|
|
const query = filterXSS(rawSearchTerm);
|
|
const divForDecode = document.createElement('div');
|
|
divForDecode.innerHTML = query;
|
|
|
|
return divForDecode.firstChild !== null
|
|
? divForDecode.firstChild.nodeValue
|
|
: query;
|
|
}
|
|
|
|
export function preloadSearchResults({
|
|
searchTerm,
|
|
location = window.location,
|
|
}) {
|
|
const encodedQuery = fixedEncodeURIComponent(
|
|
searchTerm.replace(/^[ ]+|[ ]+$/g, ''),
|
|
);
|
|
InstantClick.preload(
|
|
`${location.origin}/search?q=${encodedQuery}${getFilterParameters(
|
|
location.href,
|
|
)}`,
|
|
);
|
|
}
|
|
|
|
export function createSearchUrl(dataHash) {
|
|
const searchParams = new URLSearchParams();
|
|
Object.keys(dataHash).forEach((key) => {
|
|
const value = dataHash[key];
|
|
if (Array.isArray(value)) {
|
|
value.forEach((arrayValue) => {
|
|
searchParams.append(`${key}[]`, arrayValue);
|
|
});
|
|
} else {
|
|
searchParams.append(key, value);
|
|
}
|
|
});
|
|
|
|
return searchParams.toString();
|
|
}
|
|
|
|
/**
|
|
* A helper method to call /search endpoints.
|
|
*
|
|
* @param {string} endpoint - The search endpoint you want to request (i.e. tags).
|
|
* @param {object} dataHash - A hash with the search params that need to be included in the request.
|
|
*
|
|
* @returns {Promise} A promise object with response formatted as JSON.
|
|
*/
|
|
export function fetchSearch(endpoint, dataHash) {
|
|
const searchUrl = createSearchUrl(dataHash);
|
|
|
|
return request(`/search/${endpoint}?${searchUrl}`).then((response) =>
|
|
response.json(),
|
|
);
|
|
}
|