From b340e41da18651054ab82ebed0d16898fb4960a3 Mon Sep 17 00:00:00 2001 From: Ankit Gupta Date: Mon, 29 Apr 2024 18:38:57 +0530 Subject: [PATCH 1/9] Coveo Search Implementation Created New Search Block Added search CSS in search.CSSS Update the Header.js to add the new search input in header Removed the old header code Removed the old search CSS Update the template.css code for header changes Update aem.js for debounce functionality on input search Update the header CSS in gcse.css --- blocks/header/header.js | 543 +++++++++++++++------------------------ blocks/search/search.css | 98 +++++++ blocks/search/search.js | 203 +++++++++++++++ scripts/aem.js | 8 + styles/gcse.css | 255 ++++++++++++------ styles/template.css | 6 +- 6 files changed, 699 insertions(+), 414 deletions(-) create mode 100644 blocks/search/search.css create mode 100644 blocks/search/search.js diff --git a/blocks/header/header.js b/blocks/header/header.js index cea1276..9fe5ba8 100644 --- a/blocks/header/header.js +++ b/blocks/header/header.js @@ -1,202 +1,11 @@ -import { getMetadata } from '../../scripts/aem.js'; +import { debounce, getMetadata } from '../../scripts/aem.js'; +import { + input, div, ul, li, span, a, +} from '../../scripts/dom-builder.js'; const windowWidth = document.body.offsetWidth; -function createGcseTools() { - const gcseTools = document.createElement('div'); - gcseTools.id = 'mmg-gcse-tools'; - const gcseOuter = document.createElement('div'); - gcseOuter.className = 'mmg-gcse-outer'; - const closeButton = document.createElement('span'); - closeButton.className = 'close-btn'; - closeButton.innerText = '×'; - - // Add click event to close the search and remove the element from the DOM - closeButton.addEventListener('click', () => { - const searchResultsBlock = document.getElementById('mmg-gcse'); - if (searchResultsBlock) { - searchResultsBlock.remove(); - } - }); - - gcseOuter.appendChild(closeButton); - gcseTools.appendChild(gcseOuter); - return gcseTools; -} - -function truncateText(text, maxLength) { - if (text.length <= maxLength) { - return text; - } - return `${text.slice(0, maxLength)}...`; -} - -function createGcseBox() { - const gcseBox = document.createElement('div'); - gcseBox.id = 'mmg-gcse-box'; - const outer = document.createElement('div'); - outer.className = 'mmg-gcse-outer'; - outer.style.opacity = 1; - gcseBox.appendChild(outer); - return gcseBox; -} - -function createHeadingElement(input) { - const heading = document.createElement('h2'); - heading.innerText = `Search for: ${input}`; - heading.classList.add('search-title'); - return heading; -} - -function createUnifiedElement(input) { - const unified = document.createElement('span'); - unified.innerHTML = `Want to Search across all Life Sciences Companies of Danaher? Explore Danaher Unified Search`; - unified.classList.add('search-unified'); - return unified; -} - -function createCountElement(resultsLength, total) { - const count = document.createElement('p'); - count.className = 'search-info'; - count.innerText = `Results ${resultsLength} out of ${total} items`; - return count; -} - -function createResultLink(result) { - const link = document.createElement('a'); - link.classList.add('item'); - - const spanTitle = document.createElement('span'); - spanTitle.classList.add('title'); - spanTitle.textContent = truncateText(result.title, 70); - const date = new Date(Number(result.date) * 1000).toLocaleDateString('en-US', { year: 'numeric', month: 'long' }).toLowerCase(); - const description = truncateText(result.description, 150); - link.appendChild(spanTitle); - const dateNode = document.createTextNode(date); - const descriptionNode = document.createTextNode(description); - link.appendChild(dateNode); - link.appendChild(descriptionNode); - link.href = result.path; - - return link; -} - -function removeSearchResult() { - const searchResultsBlock1 = document.getElementById('mmg-gcse'); - if (searchResultsBlock1) { - searchResultsBlock1.remove(); - } -} - -function updateDisplayedItems(currentPage, itemsPerPage, container) { - const anchorTags = container.querySelectorAll('a'); - const startIndex = (currentPage - 1) * itemsPerPage; - const endIndex = startIndex + itemsPerPage; - anchorTags.forEach((element, index) => { - element.style.display = (index >= startIndex && index < endIndex) ? '' : 'none'; - }); -} - -function clearExistingPagination(container) { - const existingPagination = container.querySelector('.pagination'); - if (existingPagination) { - container.removeChild(existingPagination); - } -} - -function createPaginationDiv() { - const paginationDiv = document.createElement('div'); - paginationDiv.className = 'pagination'; - return paginationDiv; -} - -function updatePagination(currentPage, totalPages, elementsContainer) { - const itemsPerPage = 10; - updateDisplayedItems(currentPage, itemsPerPage, elementsContainer); - - // Clear existing pagination before appending new one - clearExistingPagination(elementsContainer); - - function createNavigationButton(label, isEnabled, targetPage) { - const button = document.createElement('span'); - button.className = `nav-button ${label.toLowerCase()} ${isEnabled ? '' : 'disabled'}`; - button.textContent = label; - if (isEnabled) { - button.addEventListener('click', () => updatePagination(targetPage, totalPages, elementsContainer)); - } - return button; - } - - function createPageButton(pageNumber, currentPageValue, totalPagesValue, container) { - const pageButton = document.createElement('span'); - pageButton.className = `page ${pageNumber === currentPageValue ? 'active' : ''}`; - pageButton.textContent = pageNumber; - pageButton.addEventListener('click', () => { - if (pageNumber !== currentPageValue) { - updatePagination(pageNumber, totalPagesValue, container); - } - }); - return pageButton; - } - - const pagination = createPaginationDiv(); - pagination.appendChild(createNavigationButton('Prev', currentPage > 1, currentPage - 1)); - for (let i = 1; i <= totalPages; i += 1) { - pagination.appendChild(createPageButton(i, currentPage, totalPages, elementsContainer)); - } - pagination.appendChild(createNavigationButton('Next', currentPage < totalPages, currentPage + 1)); - - elementsContainer.appendChild(pagination); -} - -function roundToNextTenth(value) { - return Math.ceil(value / 10) * 10; -} - -function createSearchResultsBlock(results, input, total) { - // Remove the main search results container if any - removeSearchResult(); - // Create the main search results container - const searchResultsBlock = document.createElement('div'); - searchResultsBlock.id = 'mmg-gcse'; - searchResultsBlock.className = 'active'; - const bodyHeight = document.body.clientHeight; - const header = document.getElementById('header'); - const headerHeight = header.clientHeight; - searchResultsBlock.style.height = `${bodyHeight - headerHeight}px`; - - // Create GCSE tools container - const gcseTools = createGcseTools(); - - // Create GCSE box container - const gcseBox = createGcseBox(); - - // Create Unified Search element - const unified = createUnifiedElement(input); - - // Create heading element - const heading = createHeadingElement(input); - - // Create count element - const count = createCountElement(results.length, total); - - // Append elements to the searchResultsBlock - const outer = gcseBox.querySelector('.mmg-gcse-outer'); - outer.appendChild(heading); - outer.appendChild(unified); - outer.appendChild(count); - - // Create individual result elements - results.forEach((result) => { - const link = createResultLink(result); - outer.appendChild(link); - }); - updatePagination(1, roundToNextTenth(results.length) / 10, outer); - searchResultsBlock.appendChild(gcseTools); - searchResultsBlock.appendChild(gcseBox); - - return searchResultsBlock; -} +let coveoSearchValue = ''; function addClassesToMenuItems(element, depth) { const childItems = element.children; @@ -216,11 +25,13 @@ function addClassesToMenuItems(element, depth) { if (childElement?.children?.length > 0) { if (windowWidth < 961) { - const spanElement = document.createElement('span'); - spanElement.className = 'arrow'; + const spanElement = span({ class: 'arrow' }); childElement.style.display = 'none'; spanElement.addEventListener('click', () => { - if (childElement.style.display === 'block' || childElement.style.display === '') { + if ( + childElement.style.display === 'block' + || childElement.style.display === '' + ) { childElement.style.display = 'none'; item.classList.remove('open'); } else { @@ -238,39 +49,177 @@ function addClassesToMenuItems(element, depth) { } } -function handleSearchFormSubmit(formElement) { - function searchFormHandler(e) { - e.preventDefault(); - const inputValue = formElement.querySelector('input').value; - fetch('/query-index.json') - .then((response) => response.json()) - .then((jsonData) => { - // Perform a search based on the fetched JSON data - const results = jsonData.data.filter((item) => { - // Customize this condition to match your search criteria - const it = (item.title.toLowerCase() - + item['sub-title'].toLowerCase() - + item.description.toLowerCase()).includes(inputValue); - return it; - }); - const resultBlock = document.querySelector('.search-results'); - if (resultBlock) { - resultBlock.remove(); - } - if (inputValue !== '') { - // Create a block based on the search results - const searchResultsBlock = createSearchResultsBlock( - results, - inputValue, - jsonData.total, - ); - document.body.appendChild(searchResultsBlock); - } else { - removeSearchResult(); - } +function getRecentSearches() { + const recentSearchesString = localStorage.getItem('coveo-recent-queries'); + const recentSearches = recentSearchesString ? JSON.parse(recentSearchesString) : []; + return recentSearches.slice(0, 3); +} + +function setRecentSearches(value) { + const recentSearches = getRecentSearches(); + const searchValueIndex = recentSearches.findIndex((search) => search === value); + if (searchValueIndex > -1) recentSearches.splice(searchValueIndex, 1); + recentSearches.unshift(value); + localStorage.setItem('coveo-recent-queries', JSON.stringify(recentSearches.slice(0, 3))); +} + +function submitSearchPage() { + const inputValue = document.querySelector('.mobile-search .coveo-search')?.value?.trim(); + if (inputValue && inputValue !== '') { + window.location = `${window.location.origin}/drafts/search#q=${inputValue}`; + } +} + +function onClickOfitems(value) { + setRecentSearches(value); + document.querySelectorAll('.coveo-search').forEach((inpEl) => { + inpEl.value = value; + inpEl.focus(); + inpEl.click(); + submitSearchPage(); + }); +} + +function toggleSearchDropdown(event, mode) { + if (mode === 'focus') { + event.target.parentElement.nextSibling.classList.add('show'); + } else if (mode === 'blur') { + setTimeout(() => { + event.target.parentElement.nextSibling.classList.remove('show'); + }, 500); + } +} + +async function addRecentSearch() { + let recentSearches = getRecentSearches(); + if (recentSearches.length > 0) { + recentSearches = recentSearches.reverse(); + const parentEls = document.querySelectorAll('div.coveo-search-dropdown-menu .all-recent-searches ul'); + parentEls.forEach((parentEl) => { + parentEl.innerHTML = ''; + recentSearches.forEach((el) => { + const item = li({ class: 'recent-search-item', onclick: () => onClickOfitems(el) }); + item.innerHTML = ` ${el}`; + parentEl.prepend(item); }); + }); + } +} + +async function buildSearchSuggestions(response) { + const parentEls = document.querySelectorAll('div.coveo-search-dropdown-menu ul.suggestions'); + if (parentEls.length > 0) { + parentEls.forEach((parentEl) => { + parentEl.innerHTML = ''; + if (response && response.completions && response.completions.length > 0) { + response?.completions?.forEach((el) => { + if (el && el.expression) { + const item = li({ onclick: () => onClickOfitems(el.expression) }); + item.innerHTML = ` ${el.expression}`; + parentEl.append(item); + } + }); + } + }); + } +} + +async function fetchSuggestions(value) { + try { + const payload = { + locale: 'en', + pipeline: 'Aldevron Marketplace', + searchHub: 'AldevronMainSearch', + timezone: 'America/New_York', + q: value, + count: 4, + referrer: '', + }; + const accessToken = 'xx36c41356-a0e5-4071-bcae-d27539d778e2'; + const resp = await fetch( + 'https://danahernonproduction1892f3fhz.org.coveo.com/rest/search/v2/querySuggest', + { + method: 'POST', + headers: { + authorization: `Bearer ${accessToken}`, + 'content-type': 'application/json', + }, + body: JSON.stringify(payload), + }, + ); + const response = await resp.json(); + buildSearchSuggestions(response); + coveoSearchValue = value; + } catch (error) { + /* eslint-disable no-console */ + console.log('Error', error); } - return searchFormHandler; +} + +function customCoveoSearch() { + const searchIcon = div({ + onclick: () => { + const mobileValue = document.querySelector('.mobile-search .coveo-search')?.value; + if (mobileValue && mobileValue !== '') { + setRecentSearches(mobileValue); + submitSearchPage(); + } + }, + }); + searchIcon.innerHTML = 'Search'; + const customSearchDiv = div( + { class: 'coveo-search-dropdown custom-search', onclick: (event) => event.stopPropagation() }, + div( + { class: 'coveo-searchbox' }, + input({ + type: 'text', + class: 'coveo-search', + placeholder: 'Search here...', + onfocus: (event) => toggleSearchDropdown(event, 'focus'), + onblur: (event) => toggleSearchDropdown(event, 'blur'), + onkeyup: debounce((event) => { + const { value } = event.target; + console.log(value); + if (event.keyCode === 13) { + submitSearchPage(); + if (value !== '') setRecentSearches(value); + } else { + document.querySelector('.mobile-search .coveo-search').value = value; + if (value === '') { + addRecentSearch(); + if (coveoSearchValue !== value) fetchSuggestions(value); + } else { + fetchSuggestions(value); + document.querySelectorAll('.all-recent-searches ul').forEach((recentEl) => { + recentEl.innerHTML = ''; + }); + document.querySelectorAll('.recent-search-item').forEach((recentItemEl) => { + recentItemEl.remove(); + }); + } + } + }, 300), + }), + searchIcon, + ), + div( + { class: 'coveo-search-dropdown-menu' }, + div( + { class: 'all-recent-searches' }, + ul(), + span({ class: 'recent-searches' }, 'Recent Searches'), + span({ + class: 'clear-recent-searches', + onclick: () => { + localStorage.removeItem('coveo-recent-queries'); + document.querySelectorAll('.recent-search-item').forEach((event) => event.parentNode.removeChild(event)); + }, + }, 'Clear'), + ), + ul({ 'aria-labelledby': 'coveo-searchbox', class: 'suggestions' }), + ), + ); + return customSearchDiv; } /** @@ -286,124 +235,52 @@ export default async function decorate(block) { if (resp.ok) { const html = await resp.text(); - const htmlElements = document.createElement('div'); + const htmlElements = div(); htmlElements.innerHTML = html; const childElements = htmlElements.querySelector('div'); // decorate nav DOM const nav = document.createElement('header'); nav.id = 'header'; - const outer = document.createElement('div'); - outer.classList.add('outer'); - // outer.innerHTML = html; + const outer = div({ class: 'outer' }); nav.appendChild(outer); - // convertToLogo(nav.children[0]); - const logo = document.createElement('a'); - logo.id = 'logo'; - logo.href = '/'; - logo.ariaLabel = 'Aldevron Logo'; + const logo = a({ id: 'logo', href: '/', 'aria-label': 'Aldevron Logo' }); logo.innerHTML = childElements.children[0].innerHTML; outer.appendChild(logo); - const headerNav = document.createElement('div'); - headerNav.id = 'header-nav'; - - const mobileNav = document.createElement('div'); - mobileNav.id = 'mobile-nav'; - const spanTag = document.createElement('span'); - spanTag.classList.add('icon-menu'); - mobileNav.appendChild(spanTag); - - mobileNav.addEventListener('click', () => { - headerNav.classList.toggle('hover'); - }); - - const headerNavIn = document.createElement('div'); - headerNavIn.id = 'header-nav-in'; - - const headerInfo = document.createElement('div'); - headerInfo.id = 'header-info'; - - // Create a div element with id, class, and inline style - const customSearchDiv = document.createElement('div'); - customSearchDiv.id = 'custom-search'; - customSearchDiv.className = ''; - customSearchDiv.style = ''; - - // Create a form element and set the data-hs-cf-bound attribute - const formElement = document.createElement('form'); - formElement.setAttribute('data-hs-cf-bound', 'true'); - formElement.setAttribute('data-gtm-form-interact-id', 0); - - // Create an input element with name, id, value, placeholder, and inline style - const inputElement = document.createElement('input'); - inputElement.name = 'q'; - inputElement.id = 'customsearch-q'; - inputElement.value = ''; - inputElement.placeholder = 'Enter text...'; - inputElement.style.display = 'none'; - inputElement.setAttribute('data-gtm-form-interact-field-id', 0); - - // Create a span element with class - const spanElement = document.createElement('span'); - spanElement.className = 'icon-search'; - - // // Add event listener to input element - spanElement.addEventListener('click', () => { - if (inputElement.style.display === 'none') { - inputElement.style.display = 'inline-block'; - customSearchDiv.classList.add('active'); - } else if (inputElement.value === '') { - inputElement.style.display = 'none'; - customSearchDiv.classList.remove('active'); - } - }); + const headerNav = div({ id: 'header-nav' }); - // Append the input element and span element to the form element - formElement.appendChild(inputElement); - formElement.appendChild(spanElement); + const mobileNav = div( + { + id: 'mobile-nav', + onclick: () => headerNav.classList.toggle('hover'), + }, + span({ class: 'icon-menu' }), + ); - // Append the form element to the custom search div - customSearchDiv.appendChild(formElement); + const headerNavIn = div({ id: 'header-nav-in' }); + const headerInfo = div({ id: 'header-info' }); - const clonedCustomSearchDiv = customSearchDiv.cloneNode(true); + // Desktop Coveo Search + const coveoSearch = customCoveoSearch(); + // Mobile Coveo Search + const clonedCustomSearchDiv = customCoveoSearch(); clonedCustomSearchDiv.classList.add('mobile-search'); - // Append the custom search div to the document body or any other parent element - outer.appendChild(clonedCustomSearchDiv); - customSearchDiv.classList.add('desktop-search'); - headerInfo.appendChild(customSearchDiv); - - const mobileSpan = clonedCustomSearchDiv.querySelector('span'); - const mobileInput = clonedCustomSearchDiv.querySelector('input'); - const mobileForm = clonedCustomSearchDiv.querySelector('form'); - - mobileSpan.addEventListener('click', () => { - if (mobileInput.style.display === 'none') { - mobileInput.style.display = 'inline-block'; - clonedCustomSearchDiv.classList.add('active'); - } else if (mobileInput.value === '') { - mobileInput.style.display = 'none'; - clonedCustomSearchDiv.classList.remove('active'); - } - }); + coveoSearch.classList.add('desktop-search'); - mobileForm.addEventListener('submit', handleSearchFormSubmit(mobileForm)); - formElement.addEventListener('submit', handleSearchFormSubmit(formElement)); - - mobileSpan.addEventListener('click', handleSearchFormSubmit(mobileForm)); - spanElement.addEventListener('click', handleSearchFormSubmit(formElement)); - - mobileInput.addEventListener('input', handleSearchFormSubmit(mobileForm)); - inputElement.addEventListener('input', handleSearchFormSubmit(formElement)); - - const listElements = document.createElement('div'); + if (!window.location.pathname.includes('/drafts/search')) { + headerInfo.appendChild(coveoSearch); + // Append the custom search div to the document body or any other parent element + outer.appendChild(clonedCustomSearchDiv); + } + const listElements = div(); listElements.innerHTML = childElements.children[1].innerHTML; const elements = listElements.querySelectorAll('li'); - elements.forEach((li) => { - const anchor = li.querySelector('a'); + elements.forEach((liEl) => { + const anchor = liEl.querySelector('a'); if (anchor) { if (anchor.parentElement.tagName === 'STRONG') { anchor.setAttribute('target', '_blank'); @@ -422,12 +299,7 @@ export default async function decorate(block) { const menuWrapper = document.createElement('div'); menuWrapper.id = 'hs_menu_wrapper_mainmenu'; - menuWrapper.classList.add( - 'hs-menu-wrapper', - 'active-branch', - 'no-flyouts', - 'hs-menu-flow-horizontal', - ); + menuWrapper.classList.add(...'hs-menu-wrapper active-branch no-flyouts hs-menu-flow-horizontal'.split(' ')); const menuList = childElements.children[2].innerHTML; // Create a temporary div element @@ -454,5 +326,8 @@ export default async function decorate(block) { outer.appendChild(headerNav); block.append(nav); + + addRecentSearch(); + fetchSuggestions(''); } } diff --git a/blocks/search/search.css b/blocks/search/search.css new file mode 100644 index 0000000..6b3fdcd --- /dev/null +++ b/blocks/search/search.css @@ -0,0 +1,98 @@ +atomic-search-box::part(wrapper) { + border-color: rgb(75 85 99); + background-color: rgb(249 250 251); + margin-top: 2rem; + margin-bottom: 1rem; +} + +atomic-search-box::part(submit-button) { + margin: auto; + margin-right: 9px; + background-color: #ec8f2d; + width: 2rem; + height: 2rem; + border-radius: 0.375rem; + text-align: center; + line-height: 1em; +} + +atomic-pager::part(next-button) { + border: none; + color: var(--atomic-primary-dark) +} + +atomic-pager::part(previous-button) { + border: none; + color: var(--atomic-primary-dark) +} + +atomic-pager::part(buttons) { + border: none; +} + +atomic-pager::part(active-page-button) { + color: var(--atomic-primary-dark) +} + +atomic-result .display-list { + position: relative; + padding-right: 20%; +} + +atomic-result .btn-right-view { + position: absolute; + top: 50%; + right: 0%; +} + +.btn-view { + background-color: #dc6016; + border: 1px solid #dc6016; + color: #fff; + margin-top: .5rem; + width: 7rem; + padding: .5rem 0; + border-radius: .375rem; + font-weight: 600; +} + +atomic-search-layout{ + text-align: left; +} + +.search-title{ + width: 100%; + display: block; + padding: 0; + margin-bottom: .5rem; + font-size: 1.5rem; + font-weight: 600; +} + +.btn-atomic-link{ + width: 7rem; + padding: .5rem 0; + border-radius: .375rem; + font-weight: 600; +} + +atomic-layout-section.atomic-pagination{ + margin-top: 3rem; + margin-bottom: 3rem; +} + +.search{ + margin: auto 6% ; +} + +@media (max-width: 540px) { + .search{ + margin: 0% ; + } +} + +@media (max-width: 820px) { + .search{ + margin: 0% ; + } +} diff --git a/blocks/search/search.js b/blocks/search/search.js new file mode 100644 index 0000000..8ce52f6 --- /dev/null +++ b/blocks/search/search.js @@ -0,0 +1,203 @@ +import { loadCSS } from '../../scripts/aem.js'; + +const searchBody = ` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +`; + +export default async function decorate(block) { + loadCSS('https://static.cloud.coveo.com/atomic/v2/themes/coveo.css'); + + (async () => { + await import('https://static.cloud.coveo.com/atomic/v2/atomic.esm.js');// eslint-disable-line + await customElements.whenDefined('atomic-search-interface'); + + const searchInterface = document.querySelector('atomic-search-interface'); + // Initialization + await searchInterface.initialize({ + accessToken: 'xx36c41356-a0e5-4071-bcae-d27539d778e2', + organizationId: 'danahernonproduction1892f3fhz', + organizationEndpoints: await searchInterface.getOrganizationEndpoints('danahernonproduction1892f3fhz'), + }); + // Trigger a first search + searchInterface.executeFirstSearch(); + })(); + block.innerHTML = searchBody; +} diff --git a/scripts/aem.js b/scripts/aem.js index d7624cb..9ac8b05 100644 --- a/scripts/aem.js +++ b/scripts/aem.js @@ -896,3 +896,11 @@ export { loadFormDelayed, getFormMeetingConfig, }; + +export function debounce(func, timeout = 300) { + let timer; + return (...args) => { + clearTimeout(timer); + timer = setTimeout(() => { func.apply(this, args); }, timeout); + }; +} diff --git a/styles/gcse.css b/styles/gcse.css index 946a5be..61b3a2c 100644 --- a/styles/gcse.css +++ b/styles/gcse.css @@ -3,26 +3,13 @@ padding: 5px; float: right; margin: -7px 0 0 15px; - border: 1px solid #fff; - border-radius: 3px + order: 1; } #custom-search.active { border-color: #ccc } -#custom-search input { - width: 140px; - padding: 0; - border: 0; - font-family: inherit; - font-size: 1em; - line-height: normal; - display: none; - box-sizing: border-box; - border-radius: 0 -} - #custom-search span { cursor: pointer } @@ -40,48 +27,11 @@ body.mmg-search-active { overflow: hidden !important } -#mmg-gcse { - position: fixed; - top: 100px; - left: 0; - width: 100%; - height: 100%; - z-index: 99; - background-color: #51585b; - background-color: rgba(81 88 91 / 95%); - text-align: center; - opacity: 0; - visibility: hidden; - transition: opacity .3s -} - .active#mmg-gcse { visibility: visible; opacity: 1 } -#mmg-gcse .mmg-gcse-outer { - width: 90%; - max-width: 900px; - margin: 0 auto; - text-align: left -} - -#mmg-gcse-tools { - position: fixed; - top: 145px; - right: 0; - z-index: 999; - width: 100%; - height: 36px; - padding-right: 17px; - box-sizing: border-box -} - -#mmg-gcse-tools .mmg-gcse-outer { - height: 100% -} - #custom-search-2 { background-color: #fff; float: left; @@ -92,14 +42,6 @@ body.mmg-search-active { box-sizing: border-box } -#custom-search-2 input { - float: left; - width: 180px; - margin: 8px 0 0 6px; - padding: 0; - border: 0 -} - #custom-search-2 span { cursor: pointer; float: right; @@ -227,13 +169,6 @@ body.mmg-search-active { padding: .6em 0 } -#mmg-gcse-blog input { - float: left; - width: 80%; - border: 0; - box-sizing: border-box -} - #mmg-gcse-blog span { float: right; width: 20%; @@ -306,22 +241,186 @@ body.mmg-search-active { text-align: center } - #custom-search input { - width: 222px; - height: 50px; - float: left; - padding: 0 10px; - background: #efefef; - box-sizing: border-box - } - .mobile-search { display: block!important; } } -@media(max-width: 374px) { - #custom-search input { - width: 166px +.coveo-search-dropdown.custom-search.mobile-search { + position: absolute !important; + right: 3rem; +} + +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; +} + +.coveo-search-dropdown { + max-width: 16rem; + height: 100%; + transition-property: all; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 150ms; + position: relative; + margin: 0; + order: 1; +} + +.coveo-search-dropdown > div.coveo-searchbox { + width: 100%; + height: inherit; + position: relative; +} + +.coveo-search-dropdown > div.coveo-searchbox input.coveo-search { + width: 16rem; + height: 100%; + display: block; + + --tw-text-opacity: 1; + + color: rgb(17 24 39 / var(--tw-text-opacity)); + font-size: 0.875rem; + line-height: 1.25rem; + padding: 0.375rem 0.625rem; + + --tw-bg-opacity: 1; + + background-color: rgb(249 250 251 / var(--tw-bg-opacity)); + + --tw-border-opacity: 1; + + border-color: rgb(209 213 219 / var(--tw-border-opacity)); + border-width: 1px; + border-radius: 0.25rem; +} + +.coveo-search-dropdown.mobile-search > div.coveo-searchbox input.coveo-search { + width: 12rem !important; +} + +.coveo-search-dropdown > div.coveo-searchbox input.coveo-search:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(59 130 246 / var(--tw-ring-opacity)); + --tw-border-opacity: 1; + + border-color: rgb(59 130 246 / var(--tw-border-opacity)); +} + +.coveo-search-dropdown > div.coveo-searchbox input.coveo-search + div { + display: flex; + align-items: center; + position: absolute; + top: 0; + bottom: 0; + inset-inline-end: 0; + padding-inline-end: 0.75rem; + cursor: pointer; +} + +.coveo-search-dropdown > div.coveo-searchbox input.coveo-search + div svg { + width: 1rem; + height: 1rem; + fill: none; +} + +.coveo-search-dropdown > div.coveo-search-dropdown-menu { + position: absolute; + width: 93%; + + --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 10%), 0 1px 2px -1px rgb(0 0 0 / 10%); + --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color); + + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); + + --tw-bg-opacity: 1; + + background-color: rgb(255 255 255 / var(--tw-bg-opacity)); + border-radius: 0.5rem; + z-index: 10; + padding: 0.5rem; +} + +@media(max-width: 820px) { + .coveo-search-dropdown > div.coveo-search-dropdown-menu { + width: 91%; } +} + +.coveo-search-dropdown > div.coveo-search-dropdown-menu:not(.show) { + display: none; +} + +.coveo-search-dropdown > div.coveo-search-dropdown-menu.show { + display: block; +} + +.coveo-search-dropdown > div.coveo-search-dropdown-menu ul { + width: 100%; + font-size: 0.875rem; + line-height: 1.25rem; + color: rgb(55 65 81); + padding: 0; + user-select: none; +} + +.coveo-search-dropdown > div.coveo-search-dropdown-menu ul li { + display: flex; + align-items: center; + column-gap: 0.5rem; + padding: 0.25rem; + text-transform: capitalize; + cursor: pointer; +} + +.coveo-search-dropdown > div.coveo-search-dropdown-menu ul li:hover { + background-color: rgb(243 244 246); + padding-left: 0.5rem; + padding-right: 0.5rem; +} + +.coveo-search-dropdown > div.coveo-search-dropdown-menu ul li svg { + width: 0.75rem; + height: 0.75rem; + fill: currentcolor; +} + +.all-recent-searches { + display: flex; + justify-content: space-between; + column-gap: 0.5rem; + align-items: center; + flex-wrap: wrap-reverse; +} + +.recent-searches { + font-size: 0.875rem; + font-weight: 700; + line-height: .75rem; + color: #767a7f; +} + +.clear-recent-searches { + font-size: 0.875rem; + line-height: 1.25rem; + text-decoration: underline; + text-decoration-style: dashed; + cursor: pointer; + color: #767a7f; +} + +div.all-recent-searches ul:empty ~ * { + display: none; +} + +.coveo-search-dropdown > div.coveo-search-dropdown-menu:has(ul.suggestions:empty) { + display: none; } \ No newline at end of file diff --git a/styles/template.css b/styles/template.css index 10f2cf0..9cdbbba 100644 --- a/styles/template.css +++ b/styles/template.css @@ -75,6 +75,9 @@ body { } #header-info { + display: flex; + column-gap: 0.5rem; + align-items: center; color: #767a7f; font-family: Brown-Ald,Helvetica,Arial,sans-serif; font-size: 15px; @@ -82,12 +85,11 @@ body { line-height: normal; position: absolute; right: 0; - top: 16px + top: 16px; } #header-info a { color: #1a1919; - padding-left: 10px; text-decoration: none } From 7fbac3985cb000941971bcb1571b17c856c1317a Mon Sep 17 00:00:00 2001 From: Ankit Gupta Date: Fri, 3 May 2024 17:55:48 +0530 Subject: [PATCH 2/9] code update for header, search and scripts --- blocks/header/header.js | 46 +++++++++++++++++++++++++++++++---------- blocks/search/search.js | 38 +++++++++++++++++++++++----------- scripts/scripts.js | 42 +++++++++++++++++++++++++++++++++++++ 3 files changed, 103 insertions(+), 23 deletions(-) diff --git a/blocks/header/header.js b/blocks/header/header.js index 9fe5ba8..d421619 100644 --- a/blocks/header/header.js +++ b/blocks/header/header.js @@ -2,6 +2,7 @@ import { debounce, getMetadata } from '../../scripts/aem.js'; import { input, div, ul, li, span, a, } from '../../scripts/dom-builder.js'; +import { getCookie } from '../../scripts/scripts.js'; const windowWidth = document.body.offsetWidth; @@ -124,20 +125,43 @@ async function buildSearchSuggestions(response) { } } +function getCoveoPayload(values) { + const userTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone; + const userTimestamp = new Date().toISOString(); + const clientId = getCookie('coveo_visitorId'); + const searchHistoryString = localStorage.getItem('__coveo.analytics.history'); + const searchHistory = searchHistoryString ? JSON.parse(searchHistoryString) : []; + const payload = { + analytics: { + clientId, + clientTimestamp: userTimestamp, + documentLocation: window.location.href, + documentReferrer: document.referrer, + originContext: 'Search', + }, + locale: 'en', + pipeline: 'Aldevron Marketplace', + searchHub: 'AldevronMainSearch', + actionsHistory: searchHistory.map(({ time, value, name }) => ({ time, value, name })), + timezone: userTimeZone, + q: values, + count: 8, + referrer: document.referrer, + visitorId: clientId, + }; + return payload; +} + async function fetchSuggestions(value) { try { - const payload = { - locale: 'en', - pipeline: 'Aldevron Marketplace', - searchHub: 'AldevronMainSearch', - timezone: 'America/New_York', - q: value, - count: 4, - referrer: '', - }; - const accessToken = 'xx36c41356-a0e5-4071-bcae-d27539d778e2'; + const payload = getCoveoPayload(value); + const organizationId = window.aldevronConfig?.searchOrg; + const accessToken = window.aldevronConfig?.searchKey; + const domain = window.aldevronConfig?.origin; + const path = window.aldevronConfig?.path; + const apiURL = `https://${organizationId}${domain}${path}`; const resp = await fetch( - 'https://danahernonproduction1892f3fhz.org.coveo.com/rest/search/v2/querySuggest', + apiURL, { method: 'POST', headers: { diff --git a/blocks/search/search.js b/blocks/search/search.js index 8ce52f6..e03d4d6 100644 --- a/blocks/search/search.js +++ b/blocks/search/search.js @@ -37,7 +37,8 @@ const searchBody = ` - - - - - - - + + + + + + + - -
+ -
diff --git a/scripts/scripts.js b/scripts/scripts.js index 9ab1bbc..f235511 100644 --- a/scripts/scripts.js +++ b/scripts/scripts.js @@ -340,6 +340,47 @@ function correctUTMFlow() { } } +function getCookie(e) { + let t = decodeURIComponent( + document.cookie.replace( + new RegExp( + `(?:(?:^|.*;)\\s*${ + encodeURIComponent(e).replace(/[\\-\\.\\+\\*]/g, '\\$&') + }\\s*\\=\\s*([^;]*).*$)|^.*$`, + ), + '$1', + ), + ) || null; + if ( + t + && ((t.substring(0, 1) === '{' + && t.substring(t.length - 1, t.length) === '}') + || (t.substring(0, 1) === '[' + && t.substring(t.length - 1, t.length) === ']')) + ) { + try { + t = JSON.parse(t); + } catch (error) { /* eslint-disable no-console */ console.log('Error', error); } + } + return t; +} + +if (window.location.host === 'www.aldevron.com') { + window.aldevronConfig = { + searchOrg: 'danaherproductionrfl96bkr', + searchKey: 'xxf0b61992-52f5-41c5-8b5d-e4770521e916', + origin: '.org.coveo.com', + path: '/rest/search/v2/querySuggest', + }; +} else { + window.aldevronConfig = { + searchOrg: 'danahernonproduction1892f3fhz', + searchKey: 'xx36c41356-a0e5-4071-bcae-d27539d778e2', + origin: '.org.coveo.com', + path: '/rest/search/v2/querySuggest', + }; +} + export function formatDateRange(startdate, enddate) { const options = { month: 'short', day: '2-digit', year: 'numeric', timeZone: 'UTC', @@ -368,3 +409,4 @@ async function loadPage() { } loadPage(); +export { getCookie }; From 9ca685c37913789d432957281acae97df99d95c9 Mon Sep 17 00:00:00 2001 From: Ankit Gupta Date: Tue, 7 May 2024 11:32:43 +0530 Subject: [PATCH 3/9] coveoua analytics implementation --- scripts/delayed.js | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/scripts/delayed.js b/scripts/delayed.js index 94f2c47..caea301 100644 --- a/scripts/delayed.js +++ b/scripts/delayed.js @@ -67,3 +67,49 @@ if (isForm()) { if (getFormMeetingConfig()) { loadFormDelayed(); } + +// coveo analytics - start +(function (c, o, v, e, O, u, a) { + a = 'coveoua'; + c[a] = c[a] + || function () { + (c[a].q = c[a].q || []).push(arguments); + }; + c[a].t = Date.now(); + + u = o.createElement(v); + u.async = 1; + u.src = e; + O = o.getElementsByTagName(v)[0]; + O.parentNode.insertBefore(u, O); +}( + window, + document, + 'script', + 'https://static.cloud.coveo.com/coveo.analytics.js/2/coveoua.js', +)); + +function sendCoveoEventPage() { + const organizationId = window.aldevronConfig?.searchOrg; + const accessToken = window.aldevronConfig?.searchKey; + + coveoua( + 'init', + accessToken, + `https://${organizationId}.analytics.org.coveo.com`, + ); + + coveoua('send', 'view', { + contentIdKey: 'permanentid', + contentIdValue: window.location.origin + window.location.pathname, + language: 'en', + username: 'anonymous', + title: document.title, + location: document.location.href, + originLevel1: 'AldevronMainSearch', + }); +} + +if (!window.location.hostname.includes('localhost')) { + sendCoveoEventPage(); +} From 51546d5ece81f4d3a44f05d4800080e654bb5aa1 Mon Sep 17 00:00:00 2001 From: Ankit Gupta Date: Wed, 8 May 2024 10:06:22 +0530 Subject: [PATCH 4/9] Search and header code update --- blocks/header/header.js | 2 +- blocks/search/search.js | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/blocks/header/header.js b/blocks/header/header.js index d421619..cc473ad 100644 --- a/blocks/header/header.js +++ b/blocks/header/header.js @@ -222,7 +222,7 @@ function customCoveoSearch() { }); } } - }, 300), + }, 100), }), searchIcon, ), diff --git a/blocks/search/search.js b/blocks/search/search.js index e03d4d6..63ca2c0 100644 --- a/blocks/search/search.js +++ b/blocks/search/search.js @@ -206,9 +206,10 @@ export default async function decorate(block) { const searchInterface = document.querySelector('atomic-search-interface'); // Initialization await searchInterface.initialize({ - accessToken: 'xx36c41356-a0e5-4071-bcae-d27539d778e2', - organizationId: 'danahernonproduction1892f3fhz', - organizationEndpoints: await searchInterface.getOrganizationEndpoints('danahernonproduction1892f3fhz'), + accessToken: window.aldevronConfig?.searchKey, + organizationId: window.aldevronConfig?.searchOrg, + organizationEndpoints: await searchInterface + .getOrganizationEndpoints(window.aldevronConfig.searchOrg), }); // Trigger a first search searchInterface.executeFirstSearch(); From 4f2b0ae0a972917133ee2984a79877bb4c692275 Mon Sep 17 00:00:00 2001 From: Shivangi Singh Date: Wed, 8 May 2024 14:50:59 +0530 Subject: [PATCH 5/9] Accessibility Issues Changes --- styles/Typo.css | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/styles/Typo.css b/styles/Typo.css index 3b5156e..74d24a7 100644 --- a/styles/Typo.css +++ b/styles/Typo.css @@ -279,7 +279,7 @@ body { a { background: transparent; - color: var(--link-color); + color: #0000EE; text-decoration: none; } @@ -620,11 +620,11 @@ input[type="button"], input[type="reset"], .hs-form input[type="submit"], input[type="submit"] { - background-color: var(--primary-color); + background-color: #ffd000; border-radius: 5px!important; - border: 1px solid var(--primary-color); + border: 1px solid #ffd000; box-sizing: border-box; - color: var(--text-color); + color: #221107; cursor: pointer; display: inline-block; font-family: Brown-Ald, Helvetica, Arial, sans-serif; @@ -689,8 +689,8 @@ button:hover, input[type="button"]:hover, input[type="reset"]:hover, input[type="submit"]:hover { - background-color: #fff; - color: var(--primary-color)!important; + background-color: #221107; + color: #ffd000 !important; text-decoration: none; border: 1px solid var(--primary-color); } @@ -1757,11 +1757,14 @@ form.hs-form .hs-input[type="checkbox"] { color: #0d233e; } -.hero-carousel a { - background-color: #e46b29; +.hero-carousel a, +.grey-article-outer a.button, +.bg-grey a.button, +.grey-forms .hs-form input[type="submit"] { + background-color: #221107; border-radius: 5px; box-shadow: 0 2px 4px rgba(0 0 0 / 26%); - color: #fff; + color: #EDEDED; display: inline-block; font-size: 19px; font-weight: 700; @@ -1772,10 +1775,13 @@ form.hs-form .hs-input[type="checkbox"] { transition: all .3s } -.hero-carousel a:hover { - background-color: #1a1919; +.hero-carousel a:hover, +.grey-article-outer a.button:hover, +.bg-grey a.button:hover, +.grey-forms .hs-form:hover input[type="submit"] { + background-color: #EDEDED; border-color: #1a1919; - color: #fff; + color: #221107 !important; } .hero-carousel h2 { From 10e5cfc8705d2774f400439ac58488620af279ae Mon Sep 17 00:00:00 2001 From: Ankit Gupta Date: Thu, 9 May 2024 13:19:35 +0530 Subject: [PATCH 6/9] Removed border from the button --- styles/Typo.css | 1 + 1 file changed, 1 insertion(+) diff --git a/styles/Typo.css b/styles/Typo.css index 74d24a7..fd4dcaf 100644 --- a/styles/Typo.css +++ b/styles/Typo.css @@ -1764,6 +1764,7 @@ form.hs-form .hs-input[type="checkbox"] { background-color: #221107; border-radius: 5px; box-shadow: 0 2px 4px rgba(0 0 0 / 26%); + border: none; color: #EDEDED; display: inline-block; font-size: 19px; From 9c2a37d847f78a2c09f6058f78cd5dde4ab9621f Mon Sep 17 00:00:00 2001 From: Ankit Gupta Date: Thu, 9 May 2024 19:26:49 +0530 Subject: [PATCH 7/9] fixed lint issue and css --- scripts/delayed.js | 7 ++++--- styles/Typo.css | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/scripts/delayed.js b/scripts/delayed.js index caea301..65fe3c0 100644 --- a/scripts/delayed.js +++ b/scripts/delayed.js @@ -69,6 +69,7 @@ if (getFormMeetingConfig()) { } // coveo analytics - start +/* eslint-disable */ (function (c, o, v, e, O, u, a) { a = 'coveoua'; c[a] = c[a] @@ -88,18 +89,18 @@ if (getFormMeetingConfig()) { 'script', 'https://static.cloud.coveo.com/coveo.analytics.js/2/coveoua.js', )); - +/* eslint-enable */ function sendCoveoEventPage() { const organizationId = window.aldevronConfig?.searchOrg; const accessToken = window.aldevronConfig?.searchKey; - coveoua( + coveoua(// eslint-disable-line 'init', accessToken, `https://${organizationId}.analytics.org.coveo.com`, ); - coveoua('send', 'view', { + coveoua('send', 'view', {// eslint-disable-line contentIdKey: 'permanentid', contentIdValue: window.location.origin + window.location.pathname, language: 'en', diff --git a/styles/Typo.css b/styles/Typo.css index fd4dcaf..58aa1aa 100644 --- a/styles/Typo.css +++ b/styles/Typo.css @@ -279,7 +279,7 @@ body { a { background: transparent; - color: #0000EE; + color: #00EE; text-decoration: none; } From ee479daeaa9ad3df1ab463813b34e9b59bd8ba42 Mon Sep 17 00:00:00 2001 From: Ankit Gupta Date: Thu, 9 May 2024 19:34:41 +0530 Subject: [PATCH 8/9] removed search page from drafts --- blocks/header/header.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/blocks/header/header.js b/blocks/header/header.js index cc473ad..872e5eb 100644 --- a/blocks/header/header.js +++ b/blocks/header/header.js @@ -67,7 +67,7 @@ function setRecentSearches(value) { function submitSearchPage() { const inputValue = document.querySelector('.mobile-search .coveo-search')?.value?.trim(); if (inputValue && inputValue !== '') { - window.location = `${window.location.origin}/drafts/search#q=${inputValue}`; + window.location = `${window.location.origin}/search#q=${inputValue}`; } } @@ -293,7 +293,7 @@ export default async function decorate(block) { clonedCustomSearchDiv.classList.add('mobile-search'); coveoSearch.classList.add('desktop-search'); - if (!window.location.pathname.includes('/drafts/search')) { + if (!window.location.pathname.includes('/search')) { headerInfo.appendChild(coveoSearch); // Append the custom search div to the document body or any other parent element outer.appendChild(clonedCustomSearchDiv); From 6b6af70c7e1ed4aa4da9a18bbb02c3dc0b7a2908 Mon Sep 17 00:00:00 2001 From: Ankit Gupta Date: Fri, 10 May 2024 20:45:52 +0530 Subject: [PATCH 9/9] cross browser compatibility --- blocks/header/header.js | 11 ++++++++--- styles/gcse.css | 2 ++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/blocks/header/header.js b/blocks/header/header.js index 872e5eb..204fd90 100644 --- a/blocks/header/header.js +++ b/blocks/header/header.js @@ -58,7 +58,9 @@ function getRecentSearches() { function setRecentSearches(value) { const recentSearches = getRecentSearches(); - const searchValueIndex = recentSearches.findIndex((search) => search === value); + const searchValueIndex = recentSearches.findIndex((search) => ( + search.toLowerCase() === value.toLowerCase() + )); if (searchValueIndex > -1) recentSearches.splice(searchValueIndex, 1); recentSearches.unshift(value); localStorage.setItem('coveo-recent-queries', JSON.stringify(recentSearches.slice(0, 3))); @@ -67,6 +69,9 @@ function setRecentSearches(value) { function submitSearchPage() { const inputValue = document.querySelector('.mobile-search .coveo-search')?.value?.trim(); if (inputValue && inputValue !== '') { + document.querySelectorAll('.coveo-search').forEach((searchInputEl) => { + searchInputEl.blur(); + }); window.location = `${window.location.origin}/search#q=${inputValue}`; } } @@ -198,12 +203,13 @@ function customCoveoSearch() { input({ type: 'text', class: 'coveo-search', + value: '', + autocomplete: 'off', placeholder: 'Search here...', onfocus: (event) => toggleSearchDropdown(event, 'focus'), onblur: (event) => toggleSearchDropdown(event, 'blur'), onkeyup: debounce((event) => { const { value } = event.target; - console.log(value); if (event.keyCode === 13) { submitSearchPage(); if (value !== '') setRecentSearches(value); @@ -350,7 +356,6 @@ export default async function decorate(block) { outer.appendChild(headerNav); block.append(nav); - addRecentSearch(); fetchSuggestions(''); } diff --git a/styles/gcse.css b/styles/gcse.css index 61b3a2c..f914147 100644 --- a/styles/gcse.css +++ b/styles/gcse.css @@ -357,6 +357,7 @@ body.mmg-search-active { .coveo-search-dropdown > div.coveo-search-dropdown-menu:not(.show) { display: none; + padding: 0 !important; } .coveo-search-dropdown > div.coveo-search-dropdown-menu.show { @@ -423,4 +424,5 @@ div.all-recent-searches ul:empty ~ * { .coveo-search-dropdown > div.coveo-search-dropdown-menu:has(ul.suggestions:empty) { display: none; + padding: 0 !important; } \ No newline at end of file