Browse Source

Update search controller

pull/2535/head
Kat 2 years ago committed by kosiakkatrina
parent
commit
0e15aff139
  1. 39
      app/frontend/controllers/search_controller.js
  2. 33
      app/frontend/modules/search.js

39
app/frontend/controllers/search_controller.js

@ -1,18 +1,26 @@
import { Controller } from '@hotwired/stimulus'
import accessibleAutocomplete from 'accessible-autocomplete'
import 'accessible-autocomplete/dist/accessible-autocomplete.min.css'
import { searchSuggestion, fetchAndPopulateSearchResults } from '../modules/search'
import { searchSuggestion, fetchAndPopulateSearchResults, confirmSelectedOption, searchableName } from '../modules/search'
let hints = []
const populateHint = (results) => {
hints = results
const options = []
const populateOptions = (results, selectEl) => {
selectEl.innerHTML = ''
Object.keys(results).forEach((key) => {
const option = document.createElement('option')
option.value = key
option.innerHTML = searchableName(results[key])
option.setAttribute('data-hint', results[key].hint)
option.textContent = searchableName(results[key])
selectEl.appendChild(option)
options.push(option)
})
}
export default class extends Controller {
connect () {
const selectEl = this.element
const selectOptions = Array.from(selectEl.options).filter(function (option, index, arr) { return option.value !== '' })
const matches = /^(\w+)\[(\w+)\]$/.exec(selectEl.name)
const rawFieldName = matches ? `${matches[1]}[${matches[2]}_raw]` : ''
const relativeUrlRoute = JSON.parse(this.element.dataset.info).relative_url_route
@ -22,26 +30,13 @@ export default class extends Controller {
selectElement: selectEl,
minLength: 1,
source: (query, populateResults) => {
fetchAndPopulateSearchResults(query, populateResults, populateHint, relativeUrlRoute)
fetchAndPopulateSearchResults(query, populateResults, relativeUrlRoute, populateOptions, selectEl)
},
autoselect: true,
placeholder: 'Start typing to search',
templates: { suggestion: (value) => searchSuggestion(value, hints) },
templates: { suggestion: (value) => searchSuggestion(value, options) },
name: rawFieldName,
onConfirm: (val) => {
const selectedOption = [].filter.call(
Array.from(selectEl.options).filter(function (option, index, arr) { return option.value !== '' }),
(option) => option.value === val
)[0]
if (selectedOption) selectedOption.selected = true
}
})
const parentElement = selectEl.parentElement
const inputElement = parentElement.querySelector('[role=combobox]')
inputElement.addEventListener('input', () => {
selectOptions.forEach((option) => { option.selected = false })
onConfirm: (val) => confirmSelectedOption(selectEl, val)
})
}
}

33
app/frontend/modules/search.js

@ -117,11 +117,11 @@ export const suggestion = (value, options) => {
}
}
export const searchSuggestion = (value, hints) => {
export const searchSuggestion = (value, options) => {
try {
const result = hints[value.toString()]
const result = enhanceOption(options.find((o) => o.innerHTML === value))
if (result) {
const html = result.append ? `<span class="autocomplete__option__append">${result.value}</span> <span>${result.append}</span>` : `<span>${result.value}</span>`
const html = result.append ? `<span class="autocomplete__option__append">${result.text}</span> <span>${result.append}</span>` : `<span>${result.text}</span>`
return result.hint ? `${html}<div class="autocomplete__option__hint">${result.hint}</div>` : html
} else {
return '<span>No results found</span>'
@ -143,17 +143,22 @@ export const enhanceOption = (option) => {
}
}
export const fetchAndPopulateSearchResults = async (query, populateResults, populateHint, relativeUrlRoute) => {
export const fetchAndPopulateSearchResults = async (query, populateResults, relativeUrlRoute, populateOptions, selectEl) => {
if (/\S/.test(query)) {
const results = await fetchUserOptions(query, relativeUrlRoute)
populateResults(Object.keys(results))
populateHint(results)
populateOptions(results, selectEl)
populateResults(Object.values(results).map((o) => searchableName(o)))
}
}
export const fetchUserOptions = async (query, relativeUrlRoute) => {
try {
const response = await fetch(`${relativeUrlRoute}/users/search?query=${encodeURIComponent(query)}`)
let response
if (relativeUrlRoute) {
response = await fetch(`${relativeUrlRoute}/users/search?query=${encodeURIComponent(query)}`)
} else {
response = await fetch(`/users/search?query=${encodeURIComponent(query)}`)
}
const results = await response.json()
return results
} catch (error) {
@ -165,3 +170,17 @@ export const fetchUserOptions = async (query, relativeUrlRoute) => {
export const getSearchableName = (option) => {
return option.getAttribute('data-hint') ? option.text + ' ' + option.getAttribute('data-hint') : option.text
}
export const searchableName = (option) => {
return option.value + ' ' + option.hint
}
export const confirmSelectedOption = (selectEl, val) => {
const arrayOfOptions = Array.from(selectEl.options).filter(function (option, index, arr) { return option.value !== '' })
const selectedOption = [].filter.call(
arrayOfOptions,
(option) => option.innerHTML === val
)[0]
if (selectedOption) selectedOption.selected = true
}

Loading…
Cancel
Save