Source Code for /public/js/search.js

(function() {
  const searchForm = document.getElementById('search-form');
  const searchResults = document.getElementById('search-results');
  const searchResultsList = document.getElementById('search-results-list');
  const pages = {};
  let liveSearchDebounce;

  const searchIndex = lunr(function() {
    this.field('title')
    this.field('body')

    JSON.parse(document.getElementById('search-index').textContent).forEach(item => {
      pages[item.id] = item;
      this.add(item);
    });
  });

  function performSearch(){
    const query = searchForm.querySelector('input[name="q"]').value;

    // Use History API to update URL with ?q=...
    history.pushState({}, '', `?q=${query}`);

    // If the search term seems short, treat as a non-search:
    if( query.length < 3 ) {
      searchResults.style.display = 'none';
      return;
    }

    // Search the index:
    const results = searchIndex.search(query);
    searchResults.style.display = 'block';
    if(results.length === 0) {
      searchResultsList.innerHTML = '<li>No results found</li>';
    } else {
      searchResultsList.innerHTML = '';
      results.forEach(result => {
        const resultItem = document.createElement('li');
        const page = pages[result.ref];
        resultItem.innerHTML = `<a href="${result.ref}">${page.title}</a>`;
        searchResultsList.appendChild(resultItem);
      });
    }
  }

  // When submitting the search form, perform the search:
  searchForm.addEventListener('submit', event => {
    event.preventDefault();
    performSearch();
  });

  // When any field in the search form changes, wait 300ms and, if no other changes have occurred, perform the search:
  searchForm.addEventListener('input', event => {
    clearTimeout(liveSearchDebounce);
    liveSearchDebounce = setTimeout(performSearch, 300);
  });

  // Perform a search immediately when the page loads, in case a query was provided in the URL:
  performSearch();
})();