front_findstr-search_src_search.js

import { parseFilters, parseSort } from './helpers';
import { Handlebars } from './handlebars';
import { MeiliSearch } from 'meilisearch';

let index = null;
const findstr = window.findstr || {};
let currentAbortController = null;

try {
	const client = new MeiliSearch( {
		host: findstr.config.host,
		apiKey: findstr.config.publicKey,
	} );
	index = client.index( findstr.config.index );
} catch ( error ) {
	console.warn( error );
}

async function search(
	query,
	parameters = {},
	group = '',
	field = null,
	currentElement = null,
	useAbortController = true,
	isDisableSearchAsYouType = false,
	triggerEvent = 'input',
	keyValue = null
) {
	if ( ! parameters.filter ) {
		parameters.filter = { clauses: {} };
	}

	if ( isDisableSearchAsYouType && 'keyup' === triggerEvent && 'Enter' !== keyValue ) {
		return new Promise( () => {} );
	}

/**
 *  Limit the search field to 3 characters minimum
 *
 * @hook findstrQueryMinLength
 *
 * @param {number} queryMinLength - The minimum length of the query
 * @param {string} group          - The group name
 * @param {Object} field          - The field object
 * @param {Object} currentElement - The current element who triggered the event
 * @param {Object} parameters     - The search parameters
 *
 * @return {number} queryMinLength - The minimum length of the query
 */
const queryMinLength = findstr.hooks.applyFilters(
	'findstrQueryMinLength',
	2,
	group,
	field,
	currentElement,
	parameters
);
if ( field && field.type === 'search' && parameters.q ) {
	if ( parameters.q.length <= queryMinLength && parameters.q.length > 0 ) {
		return new Promise( () => {} );
	}
}

	const queryClone = JSON.parse( JSON.stringify( parameters ) ); //clone the object query;

	queryClone.filter = parseFilters( parameters.filter );
	queryClone.sort = parseSort( parameters.sort );

	/**
	 * Triggered before the search is performed.
	 *
	 * @hook beforeSearch
	 *
	 * @param {string} group           - The group name
	 * @param {Object} parameters      - The search parameters
	 * @param {Object} field           - The field object
	 * @param {Object} current_element - The current element who triggered the event
	 * @param {Object} index           - The meilisearch index
	 */
	findstr.hooks.doAction(
		'beforeSearch',
		group,
		parameters,
		field,
		currentElement,
		index
	);

	// Annuler la recherche précédente si elle existe
	if ( useAbortController && currentAbortController ) {
		currentAbortController.abort(
			'Findstr search aborted by a new search request'
		);
	}

	// Créer un nouveau AbortController pour cette recherche
	if ( useAbortController ) {
		currentAbortController = new AbortController();
	}

	// Options pour fetch avec le signal d'AbortController si nécessaire
	const options = useAbortController
		? { signal: currentAbortController.signal }
		: {};

	return await index
		.search( query, queryClone, options )
		.then( ( results ) => {
			results.translations = findstr.translations;
			results.hits.forEach( ( hit ) => {
				hit.post_type_label =
					findstr.translations?.post_type?.[ hit.post_type ] ??
					hit.post_type;
			} );

			results.totalHits =
				results.facetDistribution?.language?.[ findstr.currentLanguage ] ||
				results.totalHits;

			/**
			 * Filter the search results
			 *
			 * @hook searchResults
			 *
			 * @param {Object} results         - The search results
			 * @param {string} group           - The group name
			 * @param {Object} field           - The field object
			 * @param {Object} current_element - The current element who triggered the event
			 * @param {Object} parameters      - The search parameters
			 *
			 * @return {Object} results - The search results
			 */
			results = findstr.hooks.applyFilters(
				'searchResults',
				results,
				group,
				field,
				currentElement,
				parameters
			);

			/**
			 * Triggered when the search results are loaded
			 *
			 * @hook searchResults
			 *
			 * @param {Object} results         - The search results
			 * @param {string} group           - The group name
			 * @param {Object} field           - The field object
			 * @param {Object} current_element - The current element who triggered the event
			 * @param {Object} parameters      - The search parameters
			 * @param {Object} index           - The meilisearch index
			 */
			findstr.hooks.doAction(
				'searchResults',
				results,
				group,
				field,
				currentElement,
				parameters,
				index
			);

			if ( group ) {
				const resultsTemplate = Handlebars.compile(
					document.querySelector(
						`[data-findstr-results="${ group }"] .findstrResultsTemplate`
					).innerHTML
				);
				const resultsContainer = document.querySelector(
					`[data-findstr-results="${ group }"] .findstrResultsContainer`
				);

				/**
				 * Append the search results.
				 *
				 * Check if we need to replace the results or append them,
				 * If the filter returns true, we append the results, otherwise we replace them.
				 *
				 * Usage: infinite scroll or load more button
				 *
				 * @hook appendResults
				 *
				 * @param {boolean} append           - Append the results
				 * @param {Object}  results          - The search results
				 * @param {string}  group            - The group name
				 * @param {Object}  field            - The field object
				 * @param {Object}  current_element  - The current element who triggered the event
				 * @param {Object}  parameters       - The search parameters
				 * @param {Object}  resultsContainer - The results container
				 *
				 * @return {boolean} append - Append the results
				 */
				const appendResults = findstr.hooks.applyFilters(
					'appendResults',
					false,
					results,
					group,
					field,
					currentElement,
					parameters,
					resultsContainer
				);

				appendResults
					? resultsContainer.insertAdjacentHTML(
						'beforeend',
						resultsTemplate( results )
					)
					: ( resultsContainer.innerHTML = resultsTemplate( results ) );

				//if query is empty, clear the results
				if ( ! parameters.q && ! parameters.filter ) {
					resultsContainer.innerHTML = '';
				}

				resultsContainer.scrollTop = 0;

				/**
				 * Triggered after the search results are loaded
				 *
				 * @hook afterSearchResults
				 *
				 * @param {Object} results          - The search results
				 * @param {string} group            - The group name
				 * @param {Object} field            - The field object
				 * @param {Object} current_element  - The current element who triggered the event
				 * @param {Object} parameters       - The search parameters
				 * @param {Object} resultsContainer - The results container
				 */
				findstr.hooks.doAction(
					'afterSearchResults',
					results,
					group,
					field,
					currentElement,
					parameters,
					resultsContainer
				);
			}

			findstr.query = parameters; //store the object query in the global variable
			return results;
		} )
		.catch( ( error ) => {
			console.warn( 'Findstr search error : ', error );
		} );
}

export { search };