| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127 |
- import _ from 'lodash'
- import DOMPurify from 'dompurify'
- import { formatWikiHit, searchWiki } from '../algolia-search/search-wiki'
- import { sendMB } from '../../infrastructure/event-tracking'
- import { materialIcon } from '@/features/utils/material-icon'
- export function setupSearch(formEl: Element) {
- const inputEl = formEl.querySelector('[name="subject"]') as HTMLInputElement
- const resultsContainerEl = formEl.querySelector(
- '[data-ol-search-results-container]'
- ) as HTMLElement
- const wrapperEl = formEl.querySelector(
- '[data-ol-search-results-wrapper]'
- ) as HTMLElement
- if (!inputEl || !resultsContainerEl || !wrapperEl) {
- return
- }
- let lastValue = ''
- function hideResults() {
- wrapperEl.setAttribute('hidden', '')
- }
- function showResults() {
- wrapperEl.removeAttribute('hidden')
- }
- async function handleChange() {
- const value = inputEl.value
- if (value === lastValue) return
- lastValue = value
- if (value.length < 3) {
- hideResults()
- return
- }
- DOMPurify.addHook('uponSanitizeElement', node => {
- if (node.nodeName === 'EM') {
- const strong = document.createElement('strong')
- strong.textContent = node.textContent
- node.parentNode?.replaceChild(strong, node)
- }
- })
- try {
- const { hits, nbHits } = await searchWiki(value, {
- hitsPerPage: 3,
- typoTolerance: 'strict',
- })
- resultsContainerEl.innerHTML = ''
- for (const hit of hits) {
- const { url, rawPageName, sectionName } = formatWikiHit(hit)
- const liEl = document.createElement('li')
- const linkEl = document.createElement('a')
- linkEl.className = 'dropdown-item'
- linkEl.href = url
- linkEl.target = '_blank'
- linkEl.rel = 'noopener noreferrer'
- linkEl.setAttribute('role', 'menuitem')
- liEl.append(linkEl)
- const contentWrapperEl = document.createElement('span')
- contentWrapperEl.className = 'dropdown-item-description-container'
- linkEl.append(contentWrapperEl)
- const pageNameEl = document.createElement('span')
- pageNameEl.innerHTML = DOMPurify.sanitize(rawPageName)
- contentWrapperEl.append(pageNameEl)
- if (sectionName) {
- const sectionEl = document.createElement('span')
- sectionEl.className = 'dropdown-item-description'
- sectionEl.innerHTML = DOMPurify.sanitize(sectionName)
- contentWrapperEl.append(sectionEl)
- }
- const iconEl = materialIcon('open_in_new')
- iconEl.classList.add('dropdown-item-trailing-icon')
- iconEl.setAttribute('aria-hidden', 'true')
- linkEl.append(iconEl)
- resultsContainerEl.append(liEl)
- }
- if (nbHits > 0) {
- showResults()
- sendMB('contact-form-suggestions-shown')
- } else {
- hideResults()
- }
- } catch (e) {
- hideResults()
- }
- DOMPurify.removeHook('uponSanitizeElement')
- }
- inputEl.addEventListener('input', _.debounce(handleChange, 350))
- function handleClickOutside(event: Event) {
- const target = event.target as Element
- if (!wrapperEl.contains(target) && !inputEl.contains(target)) {
- hideResults()
- }
- }
- document.addEventListener('click', handleClickOutside)
- function handleKeyDown(event: Event) {
- const keyboardEvent = event as KeyboardEvent
- if (keyboardEvent.key === 'Escape') {
- if (!wrapperEl.hasAttribute('hidden')) {
- hideResults()
- keyboardEvent.stopPropagation()
- keyboardEvent.preventDefault()
- }
- }
- }
- formEl.addEventListener('keydown', handleKeyDown)
- handleChange()
- }
|