Implementeren zoekfunctionaliteit
This commit is contained in:
parent
55c242d4b6
commit
372746317e
16 changed files with 247 additions and 13 deletions
1
static/afbeeldingen/iconen/magnifying-glass.svg
Normal file
1
static/afbeeldingen/iconen/magnifying-glass.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208zM208 352a144 144 0 1 0 0-288 144 144 0 1 0 0 288z"/></svg>
|
After Width: | Height: | Size: 481 B |
141
static/js/search.js
Normal file
141
static/js/search.js
Normal file
|
@ -0,0 +1,141 @@
|
|||
// MB: created at 2023-04-24
|
||||
|
||||
|
||||
summaryInclude = 50;
|
||||
var fuseOptions = {
|
||||
shouldSort: true,
|
||||
includeMatches: true,
|
||||
includeScore: true,
|
||||
tokenize: true,
|
||||
location: 0,
|
||||
distance: 100,
|
||||
minMatchCharLength: 1,
|
||||
keys: [
|
||||
{name: "title", weight: 0.45},
|
||||
{name: "content", weight: 0.4},
|
||||
{name: "tags", weight: 0.1},
|
||||
{name: "categories", weight: 0.05}
|
||||
]
|
||||
};
|
||||
|
||||
// =============================
|
||||
// Search
|
||||
// =============================
|
||||
|
||||
var inputBox = document.getElementById('search-query');
|
||||
if (inputBox !== null) {
|
||||
var searchQuery = param("q");
|
||||
if (searchQuery) {
|
||||
inputBox.value = searchQuery || "";
|
||||
executeSearch(searchQuery, false);
|
||||
} else {
|
||||
document.getElementById('search-results').innerHTML = '<p class="search-results-empty">Typ een woord om te zoeken of bekijk alle <a href="/tags/">tags</a>.</p>';
|
||||
}
|
||||
}
|
||||
|
||||
function executeSearch(searchQuery) {
|
||||
|
||||
show(document.querySelector('.search-loading'));
|
||||
|
||||
fetch('/searchindex.json').then(function (response) {
|
||||
if (response.status !== 200) {
|
||||
console.log('Looks like there was a problem. Status Code: ' + response.status);
|
||||
return;
|
||||
} else {
|
||||
console.log('/searchindex.json loaded');
|
||||
}
|
||||
// Examine the text in the response
|
||||
response.json().then(function (pages) {
|
||||
var fuse = new Fuse(pages, fuseOptions);
|
||||
var result = fuse.search(searchQuery);
|
||||
if (result.length > 0) {
|
||||
populateResults(result);
|
||||
} else {
|
||||
document.getElementById('search-results').innerHTML = '<p class=\"search-results-empty\">No matches found</p>';
|
||||
}
|
||||
hide(document.querySelector('.search-loading'));
|
||||
})
|
||||
.catch(function (err) {
|
||||
console.log('Fetch Error :-S', err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function populateResults(results) {
|
||||
|
||||
var searchQuery = document.getElementById("search-query").value;
|
||||
var searchResults = document.getElementById("search-results");
|
||||
|
||||
// pull template from hugo template definition
|
||||
var templateDefinition = document.getElementById("search-result-template").innerHTML;
|
||||
|
||||
results.forEach(function (value, key) {
|
||||
|
||||
var content = value.item.content;
|
||||
var snippet = "";
|
||||
var snippetHighlights = [];
|
||||
|
||||
snippetHighlights.push(searchQuery);
|
||||
snippet = content.substring(0, summaryInclude * 2) + '…';
|
||||
|
||||
//replace values
|
||||
var tags = ""
|
||||
if (value.item.tags) {
|
||||
value.item.tags.forEach(function (element) {
|
||||
tags = tags + "<a href='/tags/" + element + "'>" + "#" + element + "</a> "
|
||||
});
|
||||
}
|
||||
|
||||
var output = render(templateDefinition, {
|
||||
key: key,
|
||||
title: value.item.title,
|
||||
link: value.item.url,
|
||||
tags: tags,
|
||||
categories: value.item.categories,
|
||||
snippet: snippet
|
||||
});
|
||||
searchResults.innerHTML += output;
|
||||
|
||||
snippetHighlights.forEach(function (snipvalue, snipkey) {
|
||||
var instance = new Mark(document.getElementById('summary-' + key));
|
||||
instance.mark(snipvalue);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
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 content.
|
||||
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;
|
||||
}
|
||||
|
||||
// Helper Functions
|
||||
function show(elem) {
|
||||
elem.style.display = 'block';
|
||||
}
|
||||
function hide(elem) {
|
||||
elem.style.display = 'none';
|
||||
}
|
||||
function param(name) {
|
||||
return decodeURIComponent((location.search.split(name + '=')[1] || '').split('&')[0]).replace(/\+/g, ' ');
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue