search almost done
This commit is contained in:
		
							
								
								
									
										159
									
								
								themes/fiscleconsult/static/js/search.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										159
									
								
								themes/fiscleconsult/static/js/search.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,159 @@
 | 
			
		||||
window.addEventListener("DOMContentLoaded", function(event)
 | 
			
		||||
{
 | 
			
		||||
  var index = null;
 | 
			
		||||
  var lookup = null;
 | 
			
		||||
  var queuedTerm = null;
 | 
			
		||||
 | 
			
		||||
  var form = document.getElementById("search");
 | 
			
		||||
  var input = document.getElementById("search-input");
 | 
			
		||||
 | 
			
		||||
  form.addEventListener("submit", function(event)
 | 
			
		||||
  {
 | 
			
		||||
    event.preventDefault();
 | 
			
		||||
 | 
			
		||||
    var term = input.value.trim();
 | 
			
		||||
    if (!term)
 | 
			
		||||
      return;
 | 
			
		||||
 | 
			
		||||
    startSearch(term);
 | 
			
		||||
  }, false);
 | 
			
		||||
 | 
			
		||||
  function startSearch(term)
 | 
			
		||||
  {
 | 
			
		||||
    // Start icon animation.
 | 
			
		||||
    form.setAttribute("data-running", "true");
 | 
			
		||||
 | 
			
		||||
    if (index)
 | 
			
		||||
    {
 | 
			
		||||
      // Index already present, search directly.
 | 
			
		||||
      search(term);
 | 
			
		||||
    }
 | 
			
		||||
    else if (queuedTerm)
 | 
			
		||||
    {
 | 
			
		||||
      // Index is being loaded, replace the term we want to search for.
 | 
			
		||||
      queuedTerm = term;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
      // Start loading index, perform the search when done.
 | 
			
		||||
      queuedTerm = term;
 | 
			
		||||
      initIndex();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function searchDone()
 | 
			
		||||
  {
 | 
			
		||||
    // Stop icon animation.
 | 
			
		||||
    form.removeAttribute("data-running");
 | 
			
		||||
 | 
			
		||||
    queuedTerm = null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function initIndex()
 | 
			
		||||
  {
 | 
			
		||||
    var request = new XMLHttpRequest();
 | 
			
		||||
    request.open("GET", "/index.json");
 | 
			
		||||
    request.responseType = "json";
 | 
			
		||||
    request.addEventListener("load", function(event)
 | 
			
		||||
    {
 | 
			
		||||
      lookup = {};
 | 
			
		||||
      index = lunr(function()
 | 
			
		||||
      {
 | 
			
		||||
        // Uncomment the following line and replace de by the right language
 | 
			
		||||
        // code to use a lunr language pack.
 | 
			
		||||
 | 
			
		||||
        // this.use(lunr.nl);
 | 
			
		||||
 | 
			
		||||
        this.ref("uri");
 | 
			
		||||
 | 
			
		||||
        // If you added more searchable fields to the search index, list them here.
 | 
			
		||||
        this.field("title");
 | 
			
		||||
        this.field("content");
 | 
			
		||||
        this.field("description");
 | 
			
		||||
        this.field("categories");
 | 
			
		||||
 | 
			
		||||
        for (var doc of request.response)
 | 
			
		||||
        {
 | 
			
		||||
          this.add(doc);
 | 
			
		||||
          lookup[doc.uri] = doc;
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      // Search index is ready, perform the search now
 | 
			
		||||
      search(queuedTerm);
 | 
			
		||||
    }, false);
 | 
			
		||||
    request.addEventListener("error", searchDone, false);
 | 
			
		||||
    request.send(null);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function search(term)
 | 
			
		||||
  {
 | 
			
		||||
    var results = index.search(term);
 | 
			
		||||
    console.log(results);
 | 
			
		||||
 | 
			
		||||
    // The element where search results should be displayed, adjust as needed.
 | 
			
		||||
    var target = document.querySelector("#search-result");
 | 
			
		||||
 | 
			
		||||
    while (target.firstChild)
 | 
			
		||||
      target.removeChild(target.firstChild);
 | 
			
		||||
 | 
			
		||||
    var title = document.createElement("h1");
 | 
			
		||||
    title.id = "search-results";
 | 
			
		||||
    title.className = "list-title";
 | 
			
		||||
 | 
			
		||||
    if (results.length == 0)
 | 
			
		||||
      title.textContent = `No results found for “${term}”`;
 | 
			
		||||
    else if (results.length == 1)
 | 
			
		||||
      title.textContent = `Found one result for “${term}”`;
 | 
			
		||||
    else
 | 
			
		||||
      title.textContent = `Found ${results.length} results for “${term}”`;
 | 
			
		||||
    target.appendChild(title);
 | 
			
		||||
    document.title = title.textContent;
 | 
			
		||||
 | 
			
		||||
    var template = document.getElementById("search-result");
 | 
			
		||||
    for (var result of results)
 | 
			
		||||
    {
 | 
			
		||||
      var doc = lookup[result.ref];
 | 
			
		||||
 | 
			
		||||
      // Fill out search result template, adjust as needed.
 | 
			
		||||
      var element = template.content.cloneNode(true);
 | 
			
		||||
      element.querySelector(".summary-title-link").href =
 | 
			
		||||
          element.querySelector(".read-more-link").href = doc.uri;
 | 
			
		||||
      element.querySelector(".summary-title-link").textContent = doc.title;
 | 
			
		||||
      element.querySelector(".summary").textContent = truncate(doc.content, 70);
 | 
			
		||||
      target.appendChild(element);
 | 
			
		||||
    }
 | 
			
		||||
    title.scrollIntoView(true);
 | 
			
		||||
 | 
			
		||||
    searchDone();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // This matches Hugo's own summary logic:
 | 
			
		||||
  // https://github.com/gohugoio/hugo/blob/b5f39d23b8/helpers/content.go#L543
 | 
			
		||||
  function truncate(text, minWords)
 | 
			
		||||
  {
 | 
			
		||||
    var match;
 | 
			
		||||
    var result = "";
 | 
			
		||||
    var wordCount = 0;
 | 
			
		||||
    var regexp = /(\S+)(\s*)/g;
 | 
			
		||||
    while (match = regexp.exec(text))
 | 
			
		||||
    {
 | 
			
		||||
      wordCount++;
 | 
			
		||||
      if (wordCount <= minWords)
 | 
			
		||||
        result += match[0];
 | 
			
		||||
      else
 | 
			
		||||
      {
 | 
			
		||||
        var char1 = match[1][match[1].length - 1];
 | 
			
		||||
        var char2 = match[2][0];
 | 
			
		||||
        if (/[.?!"]/.test(char1) || char2 == "\n")
 | 
			
		||||
        {
 | 
			
		||||
          result += match[1];
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
          result += match[0];
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return result;
 | 
			
		||||
  }
 | 
			
		||||
}, false);
 | 
			
		||||
							
								
								
									
										101
									
								
								themes/fiscleconsult/static/js/search2.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								themes/fiscleconsult/static/js/search2.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,101 @@
 | 
			
		||||
let pagesIndex, searchIndex;
 | 
			
		||||
const MAX_SUMMARY_LENGTH = 100;
 | 
			
		||||
const SENTENCE_BOUNDARY_REGEX = /\b\.\s/gm;
 | 
			
		||||
const WORD_REGEX = /\b(\w*)[\W|\s|\b]?/gm;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async function initSearchIndex() {
 | 
			
		||||
    try {
 | 
			
		||||
        const response = await fetch("/index.json");
 | 
			
		||||
        pagesIndex = await response.json();
 | 
			
		||||
        searchIndex = lunr(function () {
 | 
			
		||||
            this.field("title");
 | 
			
		||||
            this.field("categories");
 | 
			
		||||
            this.field("content");
 | 
			
		||||
            this.ref("href");
 | 
			
		||||
            pagesIndex.forEach(page => this.add(page));
 | 
			
		||||
        });
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
        console.log(e);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
initSearchIndex();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function getSearchResults(query) {
 | 
			
		||||
    return searchIndex.search(query).flatMap((hit) => {
 | 
			
		||||
        if (hit.ref == "undefined") return [];
 | 
			
		||||
        let pageMatch = pagesIndex.filter((page) => page.href === hit.ref)[0];
 | 
			
		||||
        pageMatch.score = hit.score;
 | 
			
		||||
        return [pageMatch];
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getLunrSearchQuery(query) {
 | 
			
		||||
    const searchTerms = query.split(" ");
 | 
			
		||||
    if (searchTerms.length === 1) {
 | 
			
		||||
        return query;
 | 
			
		||||
    }
 | 
			
		||||
    query = "";
 | 
			
		||||
    for (const term of searchTerms) {
 | 
			
		||||
        query += `+${term} `;
 | 
			
		||||
    }
 | 
			
		||||
    return query.trim();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function searchSite(query) {
 | 
			
		||||
    const originalQuery = query;
 | 
			
		||||
    query = getLunrSearchQuery(query);
 | 
			
		||||
    let results = getSearchResults(query);
 | 
			
		||||
    return results.length
 | 
			
		||||
        ? results
 | 
			
		||||
        : query !== originalQuery
 | 
			
		||||
            ? getSearchResults(originalQuery)
 | 
			
		||||
            : [];
 | 
			
		||||
}
 | 
			
		||||
const node = document.getElementById("search-input");
 | 
			
		||||
node.addEventListener('keydown', function (event) {
 | 
			
		||||
    if (event.code === 'Enter') {
 | 
			
		||||
        event.preventDefault();
 | 
			
		||||
        var q = node.value.trim().toLowerCase();
 | 
			
		||||
        var res = searchSite(q);
 | 
			
		||||
        console.log(res);
 | 
			
		||||
        renderSearchResults(res, q);
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function renderSearchResults(results, term){
 | 
			
		||||
 | 
			
		||||
    var target = document.querySelector("#search-result");
 | 
			
		||||
    while (target.firstChild)
 | 
			
		||||
      target.removeChild(target.firstChild);
 | 
			
		||||
 | 
			
		||||
    var title = document.createElement("h1");
 | 
			
		||||
    title.id = "search-results";
 | 
			
		||||
    title.className = "list-title";
 | 
			
		||||
 | 
			
		||||
    if (results.length == 0)
 | 
			
		||||
      title.textContent = `No results found for “${term}”`;
 | 
			
		||||
    else if (results.length == 1)
 | 
			
		||||
      title.textContent = `Found one result for “${term}”`;
 | 
			
		||||
    else
 | 
			
		||||
      title.textContent = `Found ${results.length} results for “${term}”`;
 | 
			
		||||
    target.appendChild(title);
 | 
			
		||||
    document.title = title.textContent;
 | 
			
		||||
 | 
			
		||||
    var template = document.getElementById("search-result");
 | 
			
		||||
    for (var result of results)
 | 
			
		||||
    {
 | 
			
		||||
      var doc = lookup[result.ref];
 | 
			
		||||
 | 
			
		||||
      // Fill out search result template, adjust as needed.
 | 
			
		||||
      var element = template.content.cloneNode(true);
 | 
			
		||||
      element.querySelector(".summary-title-link").href =
 | 
			
		||||
          element.querySelector(".read-more-link").href = doc.uri;
 | 
			
		||||
      element.querySelector(".summary-title-link").textContent = doc.title;
 | 
			
		||||
      element.querySelector(".summary").textContent = truncate(doc.content, 70);
 | 
			
		||||
      target.appendChild(element);
 | 
			
		||||
    }
 | 
			
		||||
    title.scrollIntoView(true);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user