front_findstr-search_index.js

import domReady from '@wordpress/dom-ready';
import { createHooks } from '@wordpress/hooks';
import { _x } from '@wordpress/i18n';

const findstr = window.findstr || {};

import { search } from './src/search';

import { findstrInit } from './src/facet';

// fields
import './src/fields';

//url management
import './src/url';

import './index.scss';

import * as helpers from './src/helpers';
window.findstr.helpers = helpers;

const Handlebars = helpers.Handlebars || {};

if (
	findstr.config &&
	findstr.config.host &&
	findstr.config.publicKey &&
	findstr.config.index
) {
} else {
	console.warn('findstr is not configured', findstr.config);
}

findstr.hooks = createHooks();

domReady(() => {
	//Earliest event to allow other scripts to hook into findstr
	const firstEvent = new CustomEvent('findstrInit', {
		detail: findstr,
	});
	document.dispatchEvent(firstEvent);

	if (!findstr.config || !findstr.config.host || !findstr.config.index) {
		console.error('findstr.config is not defined');
		return;
	}

	const defaultQuery = JSON.parse(findstr.config.defaultQuery);

	findstr.search = search;

	search('', defaultQuery)
		.then((response) => {
			if ('undefined' === typeof response) {
				throw new Error(
					'Findstr Error: MeiliSearch is not running or the index is not found.'
				);
			}

			//keep original facets data
			if (!findstr.facets) {
				//resort facets alphabetically, because MeiliSearch doesn't take care of accents
				const facets = {};
				for (const [key, value] of Object.entries(
					response.facetDistribution
				)) {
					facets[key] = Object.keys(value)
						.sort(Intl.Collator().compare)
						.reduce(function (acc, k) {
							acc[k] = value[k];
							return acc;
						}, {});
				}

				/**
				 * Filter the facet distribution
				 *
				 * @hook setFacetsDistribution
				 *
				 * @param {Object} facets - The facets object
				 *
				 * @return {Object} - The filtered facets object
				 */
				findstr.facets = findstr.hooks.applyFilters(
					'setFacetsDistribution',
					facets
				);
			}

			//once we get the first response, it means findstr is fully loaded
			const event = new CustomEvent('findstrLoaded', {
				detail: response,
			});

			// Dispatch the event.
			document.dispatchEvent(event);
			/**
			 * Triggered when the search results are first loaded
			 *
			 * @hook searchResultsFirstLoad
			 *
			 * @param {Object} response - The search results
			 */
			findstr.hooks.doAction('searchResultsFirstLoad', response);

			findstrInit();
		})
		.catch((error) => {
			console.error('Findstr search error', error);
		});

	findstr.clearResults = function (group) {
		const resultsContainer = document.querySelector(
			`[data-findstr-results="${group}"] .findstrResultsTemplate`
		);
		resultsContainer.innerHTML = '';
	};

	findstr.resetFilters = function (group, launchSearch = true) {
		const resultsContainer = document.querySelector(
			`[data-findstr-results="${group}"]`
		);
		if (resultsContainer) {
			const query = JSON.parse(resultsContainer.dataset.findstrQuery);
			/**
			 * Triggered when the filters are reset
			 * @hook resetFilters
			 *
			 * @param {string} group - The group name
			 */
			findstr.hooks.doAction('resetFilters', group, query);
      if( true === launchSearch ) {
        findstr.search('', query, group);
      }
		}
	};

	/* empty alert */
	if (findstr) {
		const setEmptyAlert = (group, resultsCount) => {
			const emptyAlertContainer = document.querySelector(
				'.findstr-empty-alert[data-group="' + group + '"]'
			);
			if (emptyAlertContainer) {
				const emptyAlertTemplate = Handlebars.compile(
					document.querySelector(
						`[data-group="${group}"].findstrEmptyResultsTemplate`
					).innerHTML
				);

				if (emptyAlertContainer.classList.contains('visible')) {
					emptyAlertContainer.classList.remove('visible');
					emptyAlertContainer.innerHTML = '';
				}
				setTimeout(() => {
					if (0 === resultsCount) {
						emptyAlertContainer.classList.add('visible');
						emptyAlertContainer.innerHTML = emptyAlertTemplate(
							/**
							 * Filter the data for the empty results alert.
							 *
							 * By default, emptyResultsText is set to "No results found. Please try again."
							 * The data is used in the empty alert template `empty-results.hbs.php`
							 *
							 * @hook findstrEmptyResultsData
							 * @param {Object} data - The data
							 *
							 * @return {Object} - The filtered data
							 */
							findstr.hooks.applyFilters(
								'findstrEmptyResultsData',
								{
									emptyResultsText: _x(
										'No results found. Please try again.',
										'search results',
										'findstr'
									),
								}
							)
						);
					}
				}, 150);
			}
		};

		findstr.hooks.addAction(
			'searchResults',
			'findstr-search',
			(results, group) => {
				setEmptyAlert(group, results.hits.length);
			}
		);

		findstr.hooks.addAction('findstrInit', 'findstr-search', (findstr) => {
			const resultsContainers =
				document.querySelectorAll('.findstr-results');
			resultsContainers.forEach((resultsContainer) => {
				const group = resultsContainer.dataset.findstrResults;
				const container = resultsContainer.querySelector(
					'.findstrResultsContainer'
				);

				/**
				 * When this filter is set to false, the empty alert will not be shown on first page load.
				 *
				 * @hook findstrEmptyResultsMessageOnInit
				 *
				 * @param {boolean} setEmptyAlertOnInit - Set the empty alert on init
				 * @param {string}  group               - The group name
				 *
				 * @return {boolean} - Set the empty alert on init (true by default)
				 */
				const setEmptyAlertOnInit = findstr.hooks.applyFilters(
					'findstrEmptyResultsMessageOnInit',
					true,
					group,
					resultsContainer
				);
				//if setEmptyAlertOnInit is false, it means we don't want to show the empty alert on init
				if (true === setEmptyAlertOnInit) {
					setEmptyAlert(group, container.childElementCount);
				}
			});
		});
	}
});

/* search block */

domReady(() => {
	const searchBlocks = document.querySelectorAll('.search-findstr-block');

	if (0 < searchBlocks.length) {
		searchBlocks.forEach((searchBlock) => {
			const searchInput = searchBlock.querySelector('input[type=search]');

			searchInput.addEventListener('input', () => {
				if ('' === searchInput.value) {
					searchBlock.classList.remove('dropdown-active');
				} else {
					searchBlock.classList.add('dropdown-active');
				}
			});

			window.addEventListener('click', (e) => {
				const outsideClick = !searchBlock.contains(e.target);

				if (
					outsideClick &&
					searchBlock.classList.contains('dropdown-active')
				) {
					searchBlock.classList.remove('dropdown-active');
				} else if (
					!outsideClick &&
					!searchBlock.classList.contains('dropdown-active') &&
					'' !== searchInput.value
				) {
					searchBlock.classList.add('dropdown-active');
				}
			});
		});
	}
});