/* eslint-disable object-shorthand */ /* eslint-disable prefer-arrow-callback */ /* eslint-disable vars-on-top */ /* eslint-disable strict */ /* eslint-disable no-var */ /* eslint-disable complexity */ (async function(algolia) { 'use strict'; var instantsearch = algolia.externals.instantsearch; var algoliasearch = algolia.externals.algoliasearch; var searchBox = algolia.externals.widgets.searchBox; var stats = algolia.externals.widgets.stats; var sortBy = algolia.externals.widgets.sortBy; var clearRefinements = algolia.externals.widgets.clearRefinements; var panel = algolia.externals.widgets.panel; var hits = algolia.externals.widgets.hits; var pagination = algolia.externals.widgets.pagination; var configure = algolia.externals.widgets.configure; var index_suffix = await algolia.config.index_suffix; var connectCurrentRefinements = algolia.externals.connectors.connectCurrentRefinements; var collectionPageEnabled = algolia.is_collection_results_page && algolia.config.instant_search_enabled_on_collection; if (!algolia.full_results && !algolia.is_collection_results_page) { /** * If we aren't on the search page and neither on a collection page, * then there's no need to proceed */ return; } else if (algolia.full_results) { /** * If we are on the search page and instant search isn't enabled, * then there's no need to proceed */ if (!algolia.config.instant_search_enabled) { return; } } else if (algolia.is_collection_results_page) { /** * If we are on a collection page and instant search on collection isn't * enabled, then there's no need to proceed */ if (!algolia.config.instant_search_enabled_on_collection) { return; } } /** * Array which will contain all filters to be applied while initiating the * search API call. */ var searchFilters = []; var collectionFacetFilter = null; var collectionRulesContextValue = null; var collectionHandle = null; if (collectionPageEnabled) { var matches = window.location.pathname.match(/\/collections\/([^/]+)/i); collectionHandle = Boolean(matches) && matches.length === 2 ? matches[1] : null; if (algolia.config.collection_id_indexing) { collectionFacetFilter = algolia.current_collection_id ? 'collection_ids:"' + algolia.current_collection_id + '"' : null; } else { collectionFacetFilter = 'collections:"' + collectionHandle + '"'; } // Add the collection filter to the list of search filters searchFilters.push(collectionFacetFilter); collectionRulesContextValue = algolia.config.collection_id_query_rules ? algolia.current_collection_id : collectionHandle; } // Filters for stock policy var stockPolicyFilter = null; if (algolia.config.stock_policy) { if (algolia.config.stock_policy === 'allow') { /** * For 'allow', we don't need to add any filter as we want to continue * displaying all out of stock items. */ } else if (algolia.config.stock_policy === 'deny') { // For 'deny' we will filter out all items based on inventory quantity stockPolicyFilter = 'inventory_quantity > 0'; } else if (algolia.config.stock_policy === 'continue') { /** * For 'continue' we will filter on `inventory_available` attribute whose * value is dependent on: * `inventory_quantity > 0 OR inventory_policy == 'continue'` */ stockPolicyFilter = 'inventory_available:true'; } // Add the stock policy filter to the list of search filters if (stockPolicyFilter) { searchFilters.push(stockPolicyFilter); } } var results_selector = collectionPageEnabled ? algolia.config.collection_css_selector : algolia.config.results_selector; var activeSortOrders = collectionPageEnabled && algolia.collectionSortOrders ? algolia.collectionSortOrders : algolia.sortOrders; results_selector += ', .algolia-shopify-instantsearch'; function getTrackedUiState(uiState) { var trackedUiState = {}; Object.keys(uiState).forEach(function(k) { if (k === 'configure' || k === 'query' || k === 'q') { return; } trackedUiState[k] = uiState[k]; }); return trackedUiState; } /** * List of URL params which are "allowed" by InstantSearch. * These parameters won't be overwritten when the search state is written * to the URL. */ var ALLOWED_FOREIGN_PARAMS = [ 'utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', ]; var foreignRouteState; function singleIndex(indexName) { return { /** * `stateToRoute` method transforms the `uiState` object from InstantSearch * into an object that will then be serialized to construct the URL. */ stateToRoute: function(uiState) { var route = getTrackedUiState(uiState[indexName] || {}); route.q = uiState[indexName].query; return Object.assign({}, foreignRouteState, route); }, /** * `routeToState` method transforms the route object into a `uiState` object * so that InstantSearch is initialized with the correct state from the * URL. */ routeToState: function(routeState) { /** * Backup parameters from `routeState` into a different object * `foreignRouteState` so that we can re-inject them into the object * returned within `stateToRoute`. * This allows us to preserve the parameters specified in `ALLOWED_FOREIGN_PARAMS` * array. */ if (!foreignRouteState) { foreignRouteState = ALLOWED_FOREIGN_PARAMS.reduce(function(acc, key) { acc[key] = routeState[key]; return acc; }, {}); } var state = {}; state[indexName] = getTrackedUiState(routeState || {}); state[indexName].query = routeState.q; return state; }, }; } var instant = { colors: algolia.config.colors, distinct: Boolean(algolia.config.show_products), facets: { hidden: collectionPageEnabled && algolia.collectionHiddenFacets ? algolia.collectionHiddenFacets : algolia.hiddenFacets, shown: collectionPageEnabled && algolia.collectionShownFacets ? algolia.collectionShownFacets : algolia.shownFacets, list: collectionPageEnabled && algolia.collectionFacets ? algolia.collectionFacets : algolia.facets, widgets: collectionPageEnabled && algolia.collectionFacetsWidgets ? algolia.collectionFacetsWidgets : algolia.facetsWidgets, }, hitsPerPage: collectionPageEnabled && algolia.config.collections_full_results_hits_per_page ? algolia.config.collections_full_results_hits_per_page : algolia.config.products_full_results_hits_per_page, search: instantsearch({ searchClient: algoliasearch( algolia.config.app_id, algolia.config.search_api_key ), insights: algolia.config.analytics_enabled, indexName: algolia.config.index_prefix + 'products' + index_suffix, routing: { stateMapping: singleIndex(algolia.config.index_prefix + 'products' + index_suffix), }, searchFunction: function(searchFunctionHelper) { // Set query parameters here because they're not kept when someone // presses the Back button if set in the `init` function of a custom widget var page = searchFunctionHelper.getPage(); if (instant.distinct) { searchFunctionHelper.setQueryParameter('distinct', true); } // Assign any required filters if (searchFilters.length) { searchFunctionHelper.setQueryParameter( 'filters', searchFilters.join(' AND ') ); } // Assign any required `ruleContexts` which are required for query rules // targeting collection pages if (collectionPageEnabled) { // Collection page merchandising: // If we are on a collection page, `collectionRulesContextValue` is defined if (collectionRulesContextValue) { searchFunctionHelper.setQueryParameter('ruleContexts', [ collectionRulesContextValue.toString(), ]); } else { searchFunctionHelper.setQueryParameter('ruleContexts', []); } } searchFunctionHelper.setPage(page); searchFunctionHelper.search(); }, }), selector: results_selector + ', .algolia-shopify-instantsearch', sortOrders: activeSortOrders }; instant.search.client.addAlgoliaAgent('Shopify Integration'); algolia.instantsearch = instant; function readjust() { var width = instant.$results.offsetWidth; var suffix = 'lg'; if (width < 400) suffix = 'xs'; else if (width < 800) suffix = 'sm'; else if (width < 1200) suffix = 'md'; instant.$results.classList.remove('ais-results-size-xs'); instant.$results.classList.remove('ais-results-size-sm'); instant.$results.classList.remove('ais-results-size-md'); instant.$results.classList.remove('ais-results-size-lg'); instant.$results.classList.add('ais-results-size-' + suffix); } //Link CSS and set up CSS variables const cssFile = document.getElementById('template_algolia_instant_search.css'); document.documentElement.style.setProperty(`--main-color`, `${algolia.config.colors.main}`); document.documentElement.style.setProperty(`--secondary-color`, `${algolia.config.colors.secondary}`); document.documentElement.style.setProperty(`--highlight-bg-color`, `${algolia.helpers.hexToRGB(algolia.config.colors.highlight)}`); algolia.appendStyle(cssFile.text); if (collectionPageEnabled) { if ( document.querySelectorAll(algolia.config.collection_css_selector) .length === 0 ) { throw new Error( 'Instant search CSS selector for collection page is incorrect\nFor more info see: https://www.algolia.com/doc/integration/shopify/advanced-customization/collection-search-page/#css-selector' ); } } else if ( document.querySelectorAll(algolia.config.results_selector).length === 0 ) { throw new Error( 'Instant search CSS selector is incorrect\nFor more info see: https://www.algolia.com/doc/integration/shopify/building-search-ui/instant-search/#css-selector' ); } // Instantiating the main page instant.$results = document.querySelector(instant.selector); instant.$results.innerHTML = ''; algolia.render(algolia.instantSearchMainTemplate, instant.$results, { facets: instant.facets.list, multipleSortOrders: activeSortOrders.length > 1, }); readjust(); window.addEventListener('resize', function() { readjust(); }); // Mobile facets display instant.search.addWidgets([ { init: function() { var $button = document.querySelector('.ais-facets-button'); $button.addEventListener('click', function() { var $facets = document.querySelector('.ais-facets'); if ($facets.classList.contains('ais-facets__shown')) { $button.textContent = 'Show filters'; $facets.classList.remove('ais-facets__shown'); } else { $button.textContent = 'Hide filters'; $facets.classList.add('ais-facets__shown'); } }); }, }, ]); instant.search.addWidgets([ configure({ hitsPerPage: instant.hitsPerPage, facetingAfterDistinct: Boolean(algolia.config.show_products), }), ]); // Search input instant.search.addWidgets([ searchBox({ container: '.ais-search-box-container', placeholder: algolia.translations.searchForProduct, showReset: false, showSubmit: false, }), ]); // Logo & clear instant.search.addWidgets([ { init: function(opts) { document .querySelector('.ais-clear-input-icon') .addEventListener('click', function() { opts.helper.setQuery('').search(); var input = document.querySelector('.ais-search-box--input'); input.value = ''; input.focus(); }); }, render: function(opts) { if (!opts.state.query) { document.querySelector('.ais-clear-input-icon').style.display = 'none'; } else { document.querySelector('.ais-clear-input-icon').style.display = ''; } }, }, ]); // Stats instant.search.addWidgets([ stats({ container: '.ais-stats-container', templates: { text(data, {html}){ return algolia.instantSearchStatsTemplate(data, html) } } }), ]); // Sort orders if (activeSortOrders.length > 1) { instant.search.addWidgets([ sortBy({ container: '.ais-sort-orders-container', items: instant.sortOrders, }), ]); } // Change display instant.search.addWidgets([ { init: function() { document .querySelector('.ais-search-header .ais-change-display-block') .addEventListener('click', function() { document .querySelector( '.ais-change-display-block:not(.ais-change-display-selected)' ) .classList.add('ais-change-display-selected'); document .querySelector( '.ais-change-display-list.ais-change-display-selected' ) .classList.remove('ais-change-display-selected'); document .querySelector('.ais-results-as-list') .classList.replace('ais-results-as-list', 'ais-results-as-block'); }); document .querySelector('.ais-search-header .ais-change-display-list') .addEventListener('click', function() { document .querySelector( '.ais-change-display-list:not(.ais-change-display-selected)' ) .classList.add('ais-change-display-selected'); document .querySelector( '.ais-change-display-block.ais-change-display-selected' ) .classList.remove('ais-change-display-selected'); document .querySelector('.ais-results-as-block') .classList.replace('ais-results-as-block', 'ais-results-as-list'); }); }, }, ]); // Hidden facets var list = instant.facets.hidden.map(function(facet) { return facet.name; }); instant.search.addWidgets([ { getConfiguration: function() { return { facets: list, disjunctiveFacets: list, }; }, init: function() {}, }, ]); // Create the render function var createDataAttributes = function(refinement) { return Object.keys(refinement) .map(function(key) { return 'data-' + key + '="' + encodeURIComponent(refinement[key] || '') + '"'; }) .join(' '); }; var renderListItem = function(item) { var facet = instant.facets.list.find(function(f) { return f.name === item.label; }); return item.refinements .map(function(refinement) { return ( '