From 01f4a9d1766dd58241d13cc1d80fa29521d74515 Mon Sep 17 00:00:00 2001 From: Megan Thomas Date: Tue, 5 Mar 2024 17:06:13 -0800 Subject: [PATCH] MWPW-143591 Fix Contextual Search Duplicates --- libs/blocks/article-feed/article-feed.js | 10 ++--- libs/blocks/gnav/gnav-contextual-search.js | 47 +++++++++++----------- libs/blocks/gnav/gnav.js | 16 ++++++-- 3 files changed, 41 insertions(+), 32 deletions(-) diff --git a/libs/blocks/article-feed/article-feed.js b/libs/blocks/article-feed/article-feed.js index 761c49aea7..52015036af 100644 --- a/libs/blocks/article-feed/article-feed.js +++ b/libs/blocks/article-feed/article-feed.js @@ -71,17 +71,17 @@ export function readBlockConfig(block) { * fetches blog article index. * @returns {object} index with data and path lookup */ -export async function fetchBlogArticleIndex() { +export async function fetchBlogArticleIndex(config) { + if (blogIndex.complete) return (blogIndex); const pageSize = 500; - const { feed } = blogIndex.config; + const { feed } = config || blogIndex.config; const queryParams = `?limit=${pageSize}&offset=${blogIndex.offset}`; + blogIndex.offset += pageSize; const defaultPath = updateLinkWithLangRoot(`${getConfig().locale.contentRoot}/query-index.json`); const indexPath = feed ? `${feed}${queryParams}` : `${defaultPath}${queryParams}`; - if (blogIndex.complete) return (blogIndex); - return fetch(indexPath) .then((response) => response.json()) .then((json) => { @@ -90,8 +90,8 @@ export async function fetchBlogArticleIndex() { blogIndex.data.push(post); blogIndex.byPath[post.path.split('.')[0]] = post; }); + blogIndex.complete = complete; - blogIndex.offset = json.offset + pageSize; return blogIndex; }); diff --git a/libs/blocks/gnav/gnav-contextual-search.js b/libs/blocks/gnav/gnav-contextual-search.js index 334e0c9a9d..8f94260105 100644 --- a/libs/blocks/gnav/gnav-contextual-search.js +++ b/libs/blocks/gnav/gnav-contextual-search.js @@ -3,9 +3,10 @@ import { getArticleTaxonomy, buildArticleCard } from '../article-feed/article-he import { createTag, getConfig } from '../../utils/utils.js'; import { replaceKey } from '../../features/placeholders.js'; +const LIMIT = 12; let abortController; let articles = []; -const LIMIT = 12; +let complete = false; let lastSearch = null; function highlightTextElements(terms, elements) { @@ -52,33 +53,31 @@ function highlightTextElements(terms, elements) { }); } -async function fetchResults(signal, terms) { - let data = []; - let complete = false; - const hits = []; - if (!articles.length) { - ({ data } = await fetchBlogArticleIndex()); - articles = data; - } - while (hits.length < LIMIT && !complete && !signal.aborted) { - articles.forEach((article) => { - if (hits.length === LIMIT) { - return; - } - const { category } = getArticleTaxonomy(article); - const text = [category, article.title, article.description].join(' ').toLowerCase(); - if (terms.every((term) => text.includes(term))) { - hits.push(article); - } - }); - if (hits.length < LIMIT && !complete) { - ({ data, complete } = await fetchBlogArticleIndex()); +async function fetchResults(signal, terms, config) { + let hits = []; + + for (const article of articles) { + if (hits.length === LIMIT || signal.aborted) break; + const { category } = getArticleTaxonomy(article); + const text = [category, article.title, article.description].join(' ').toLowerCase(); + if (terms.every((term) => text.includes(term))) { + hits.push(article); } } + + if (!signal.aborted && (!articles.length || (hits.length !== LIMIT && !complete))) { + const index = await fetchBlogArticleIndex(config); + articles = index.data; + complete = index.complete; + hits = await fetchResults(signal, terms, config); + } + return hits; } -export default async function onSearchInput({ value, resultsEl, searchInputEl, advancedSearchEl }) { +export default async function onSearchInput( + { value, resultsEl, searchInputEl, advancedSearchEl, contextualConfig: config }, +) { if (!value.length) { resultsEl.innerHTML = ''; searchInputEl.classList.remove('gnav-search-input--isPopulated'); @@ -99,7 +98,7 @@ export default async function onSearchInput({ value, resultsEl, searchInputEl, a const terms = value.toLowerCase().split(' ').filter(Boolean); if (!terms.length) return; - const hits = await fetchResults(abortController.signal, terms); + const hits = await fetchResults(abortController.signal, terms, config); if (currentSearch === lastSearch) { if (!hits.length) { diff --git a/libs/blocks/gnav/gnav.js b/libs/blocks/gnav/gnav.js index 8382194540..e0811a4e1b 100644 --- a/libs/blocks/gnav/gnav.js +++ b/libs/blocks/gnav/gnav.js @@ -367,15 +367,24 @@ class Gnav { this.searchType = SEARCH_TYPE_CONTEXTUAL; } - const advancedSearchEl = searchBlock.querySelector('a'); + const advancedSearchEl = searchBlock.querySelector('a:not([href$=".json"])'); let advancedSearchWrapper = null; if (advancedSearchEl) { advancedSearchWrapper = createTag('li', null, advancedSearchEl); } + const contextualConfig = {}; + [...searchBlock.children].forEach(({ children }, index) => { + if (index === 0 || children.length !== 2) return; + const key = children[0].textContent?.toLowerCase(); + const link = children[1].querySelector('a'); + const value = link ? link.href : children[1].textContent; + contextualConfig[key] = value; + }); + const label = searchBlock.querySelector('p').textContent; const searchEl = createTag('div', { class: `gnav-search ${isContextual ? SEARCH_TYPE_CONTEXTUAL : ''}` }); - const searchBar = this.decorateSearchBar(label, advancedSearchWrapper); + const searchBar = this.decorateSearchBar(label, advancedSearchWrapper, contextualConfig); const searchButton = createTag( 'button', { @@ -395,7 +404,7 @@ class Gnav { return searchEl; }; - decorateSearchBar = (label, advancedSearchEl) => { + decorateSearchBar = (label, advancedSearchEl, contextualConfig) => { const searchBar = createTag('aside', { id: 'gnav-search-bar', class: 'gnav-search-bar' }); const searchField = createTag('div', { class: 'gnav-search-field' }, SEARCH_ICON); const searchInput = createTag('input', { @@ -417,6 +426,7 @@ class Gnav { locale, searchInputEl: searchInput, advancedSearchEl, + contextualConfig, // ToDo: Pick back up here }); });