Link
About
Using the Hugo framework, I designed and developed a simple landing page along with a blog that includes categories, tags, and a search function. I continue to update and maintain these websites.
Static Search
To prevent older blog posts from getting lost, I implemented a static search bar in the navigation bar using JavaScript. The search function scans for matching phrases in titles, content, and tags. Below is a breakdown of the script.
Search function that initializes search logic
var searchFn = function () {
var lastSearchTerm = "";
var stopwords = [
"ja", "mnie", "moje", "my", "nasze", "ty", "to", "jego", "jej", "ten", "ta", "jestem", "jest", "są", "był", "być",
"ma", "miał", "robi", "jeden", "jaka", "ale", "jeśli", "lub", "jak", "z", "przy", "dla", "z", "do",
"potem", "nie", "tak", "też", "może", "i", "oraz"
];
var normalizer = document.createElement("textarea");
var searchLimit = 40;
var minSearchLength = 2;
var isSearching = false;
Normalizes input text by removing special characters and converting to lowercase
var normalizeText = function (input) {
normalizer.innerHTML = input;
return " " + normalizer.value.trim().toLowerCase()
.replace(/[^0-9a-ząćęłńóśźż ]/gi, " ")
.replace(/\s+/g, " ") + " ";
};
Renders search results by sorting them by weight and appending them to the page
var renderResults = function (results) {
results.sort((a, b) => b.weight - a.weight);
for (var i = 0; i < results.length && i < searchLimit; i++) {
var item = results[i].item;
var resultHTML = `
<div class="container result-box">
<div class="row">
<div class="col-8 img-center">
<a href="${item.permalink}" alt="${item.showTitle}">
<img src="${item.image}" alt="${item.showTitle}" class="rounded w-100">
</a>
</div>
<div class="col-12">
<h2>
<a href="${item.permalink}">${item.showTitle}</a>
</h2>
</div>
</div>
</div>`;
$("#results").append(resultHTML);
}
};
Calculates the relevance weight of search terms in different content fields
var calculateWeight = function (terms, weight, targetText) {
var totalWeight = 0;
terms.forEach(term => {
var index = targetText.indexOf(term.term);
while (index !== -1) {
totalWeight += term.weight * weight;
index = targetText.indexOf(term.term, index + 1);
}
});
return totalWeight;
};
Executes the search by checking terms against indexed content and ranking results
var search = function (terms) {
var results = [];
searchHost.index.forEach(item => {
if (!item.tags) return;
var weight = 0;
terms.forEach(term => {
if (item.title.startsWith(term.term)) {
weight += term.weight * 32;
}
});
weight += calculateWeight(terms, 1, item.content);
item.tags.forEach(tag => {
weight += calculateWeight(terms, 4, tag);
});
weight += calculateWeight(terms, 16, item.title);
if (weight) {
results.push({ weight, item });
}
});
$("#results").html(results.length ? "<p></p>" : "<p>Brak wyników.</p>");
if (results.length) renderResults(results);
};
Initiates the search process when the user types or clicks the search button
var executeSearch = function () {
if (isSearching) return;
var searchTerm = normalizeText($("#searchBox").val()).trim();
if (searchTerm === lastSearchTerm) return;
lastSearchTerm = searchTerm;
if (searchTerm.length < minSearchLength) {
$("#btnGo").attr("disabled", true);
return;
}
$("#btnGo").removeAttr("disabled");
isSearching = true;
var terms = searchTerm.split(" ");
var searchTerms = [];
terms.forEach((_, i) => {
for (var j = i; j < terms.length; j++) {
var weight = Math.pow(2, j - i);
var phrase = terms.slice(i, j + 1).join(" ");
if (phrase.length >= minSearchLength && !stopwords.includes(phrase)) {
searchTerms.push({ weight, term: " " + phrase + " " });
}
}
});
search(searchTerms);
isSearching = false;
};
Sets up event listeners for search input and button click actions
var initSearch = function () {
$("#searchBox").keyup(executeSearch);
$("#btnGo").click(function () {
executeSearch();
window.location.href = window.location.href.split("#")[0] + "#resultsArea";
});
executeSearch();
};
Loads search index from a JSON file and initializes search functionality
var searchHost = {};
$.getJSON("/index.json", function (results) {
searchHost.index = [];
var seenLinks = {};
results.forEach(result => {
if (result.tags && !seenLinks[result.permalink]) {
searchHost.index.push({
showTitle: result.title,
title: normalizeText(result.title),
content: normalizeText(result.content),
tags: result.tags.map(tag => normalizeText(tag)),
permalink: result.permalink,
image: result.image
});
seenLinks[result.permalink] = true;
}
});
$("#loading").hide();
$("#btnGo").show();
$("#searchBox").show().removeAttr("disabled").focus();
initSearch();
});
};
Runs the search function once the page is fully loaded
window.addEventListener("DOMContentLoaded", searchFn);