var summaryInclude = 100 var fuseOptions = { shouldSort: true, includeMatches: true, threshold: 0.0, tokenize: true, location: 0, distance: 100, maxPatternLength: 32, minMatchCharLength: 2, keys: [ { name: "title", weight: 0.8 }, { name: "tags", weight: 0.3 }, { name: "categories", weight: 0.3 }, { name: "contents", weight: 0.7 } ] } var searchQuery = param("s") if (searchQuery) { $("#search-query").val(searchQuery) executeSearch(searchQuery) } else { $("#search-string").replaceWith(searchQuery) $("#search-results-length").replaceWith(0) } function executeSearch(searchQuery) { $.getJSON("/index.json", function(data) { var pages = data var fuse = new Fuse(pages, fuseOptions) var result = fuse.search(searchQuery) console.log({ matches: result }) $("#search-string").replaceWith(searchQuery) $("#search-results-length").replaceWith(result.length) if (result.length > 0) { populateResults(result) } else { $("#search-results").append("
No matches found
") } }) } function populateResults(result) { $.each(result, function(key, value) { var contents = value.item.contents var snippet = "" var snippetHighlights = [] var tags = [] if (fuseOptions.tokenize) { snippetHighlights.push(searchQuery) } else { $.each(value.matches, function(matchKey, mvalue) { if (mvalue.key == "tags" || mvalue.key == "categories") { snippetHighlights.push(mvalue.value) } else if (mvalue.key == "contents") { let startIdx = mvalue.indices[0][0] let endIdx = mvalue.indices[0][1] let start = 0 if (startIdx - summaryInclude > 0) { start = startIdx - summaryInclude } let end = contents.length if (endIdx + summaryInclude < contents.length) { endIdx + summaryInclude } snippet += contents.substring(start, end) snippetHighlights.push( mvalue.value.substring( startIdx, endIdx - startIdx + 1 ) ) } }) } if (snippet.length < 1) { snippet += contents.substring(0, summaryInclude * 2) } //pull template from hugo template definition var templateDefinition = $("#search-result-template").html() //replace values var output = render(templateDefinition, { key: key, title: value.item.title, link: value.item.permalink, tags: value.item.tags, categories: value.item.categories, snippet: snippet }) $("#search-results").append(output) $.each(snippetHighlights, function(snipkey, snipvalue) { $("#summary-" + key).mark(snipvalue) }) }) } function param(name) { return decodeURIComponent( (location.search.split(name + "=")[1] || "").split("&")[0] ).replace(/\+/g, " ") } function render(templateString, data) { var conditionalMatches, conditionalPattern, copy conditionalPattern = /\$\{\s*isset ([a-zA-Z]*) \s*\}(.*)\$\{\s*end\s*}/g //since loop below depends on re.lastInxdex, we use a copy to capture any manipulations whilst inside the loop copy = templateString while ( (conditionalMatches = conditionalPattern.exec(templateString)) !== null ) { if (data[conditionalMatches[1]]) { //valid key, remove conditionals, leave contents. copy = copy.replace(conditionalMatches[0], conditionalMatches[2]) } else { //not valid, remove entire section copy = copy.replace(conditionalMatches[0], "") } } templateString = copy //now any conditionals removed we can do simple substitution var key, find, re for (key in data) { find = "\\$\\{\\s*" + key + "\\s*\\}" re = new RegExp(find, "g") templateString = templateString.replace(re, data[key]) } return templateString }