add search functionality

This commit is contained in:
ajuvercr 2020-09-09 21:54:22 +02:00
parent 391b2a115c
commit 3dde9d6779
7 changed files with 175 additions and 5 deletions

8
Rules
View file

@ -72,6 +72,13 @@ compile '/quiz.md' do
write ext: 'html'
end
compile '/search.html.erb' do
filter :erb
layout '/default.*'
layout '/base.*'
write ext: 'html'
end
compile '/*.md' do
filter :kramdown
layout '/default.*'
@ -98,4 +105,3 @@ layout '/**/*', :erb
compile '/**/*' do
write item.identifier.to_s
end

110
content/search.html.erb Normal file
View file

@ -0,0 +1,110 @@
<div class="search">
<div class="search__main">
<form id="search_form">
<label>Test field: <input type="text"></label>
<button type="submit">Submit form</button>
</form>
</div>
<div id="search_wrapper" class="search__result"></div>
</div>
<script src="https://unpkg.com/lunr/lunr.js"></script>
<script>
function clearDiv(element) {
while (element.lastElementChild) {
element.removeChild(element.lastElementChild);
}
}
function myFunction(event) {
doSearch(event.target[0].value);
event.preventDefault();
}
const wrapper = document.getElementById("search_wrapper");
const form = document.getElementById('search_form');
form.addEventListener('submit', myFunction);
var doSearch = (e) => {};
function parseUrlParams () {
const url = window.location.search;
if(!url) return {};
const paramsBuilder = {};
for(let currentVar of url.substring(1).split("&")) {
var pair = currentVar.split('=');
paramsBuilder[pair[0]] = decodeURIComponent(pair[1]);
}
return paramsBuilder;
};
function resetFromUrl() {
const urlParams = parseUrlParams();
if(urlParams["q"]) {
doSearch(urlParams["q"]);
form[0].value = urlParams["q"];
} else {
form[0].value = "";
clearDiv(wrapper);
}
}
function ready() {
function render_results(div, partials) {
const create_wrapper= document.createElement('div');
for(let partial of partials) {
let html = "";
switch (partial.kind) {
case "vereniging":
html = `<div class="search__partial" onclick="location.href='${partial.url}';">
<p class="search__partial__titel">${partial.titel}</p>` +
(partial.themas ? `<p class="search__partial__themas"> Themas: ${(partial.themas || []).join(", ")}</p>` : "") +
`</div>`;
break;
case "konvent":
html = `<div class="search__partial" onclick="location.href='${partial.url}';">
<p class="search__partial__titel">${partial.titel}</p>
</div>`;
break;
default:
break;
}
if(html) {
create_wrapper.innerHTML = html;
div.appendChild(create_wrapper.firstChild);
}
}
}
const documents = <%= CreateFullTextIndex.new(@items.find_all("**/verenigingen/*") + @items.find_all("**/konventen/*")).call.to_json %>;
const partials = <%= Hash[(partial_konventen + partial_verenigingen).map { |x| [x[:url], x] }].to_json %>;
const index = lunr(function () {
this.field('id', {boost: 15});
this.field('title', {boost: 10});
this.field('verkort', {boost: 8});
this.field('konvent', {boost: 3});
this.field('body');
this.ref('url');
documents.forEach(function(i) { this.add(i); }, this);
});
doSearch = (query) => {
clearDiv(wrapper);
render_results(wrapper, index.search(query).map(i => partials[i.ref]));
window.history.pushState("search state", "", window.location.pathname + "?q="+query);
};
resetFromUrl();
}
document.addEventListener("DOMContentLoaded", ready);
window.addEventListener("popstate", resetFromUrl);
</script>

View file

@ -4,7 +4,7 @@ id: zeus
naam: Zeus WPI
verkorte_naam: Zeus WPI
themas:
- wetenschap-techniek
- wetenschap-techniek
konvent: wvk
logo: placeholder.png
contact: bestuur@zeus.ugent.be

View file

@ -1,13 +1,14 @@
<!DOCTYPE html>
<html lang="nl">
<head>
<meta charset="utf-8">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title> Durf Doen! - <%= item[:naam] || abbreviation(item) %> </title>
<link rel="stylesheet" href="/stylesheets/main.css">
<link rel="shortcut icon" href="/assets/favicon.png">
<%= item[:head] %>
</head>
<body>

View file

@ -15,6 +15,8 @@
</ul>
<div>
<input type="search" placeholder="Zoek vereniging, convent …">
<form action="/search.html">
<input type="search" name="q" placeholder="Zoek vereniging, convent …">
</form>
</div>
</nav>

50
lib/helpers/search.rb Normal file
View file

@ -0,0 +1,50 @@
require 'json'
require 'nokogiri'
module SearchHelper
class CreateFullTextIndex
COMMON_WORDS = %w{ a about above across ... } unless defined?(COMMON_WORDS)
def initialize(articles)
@articles = articles
end
def call
@articles.map do |item|
words = item.raw_content().downcase.split(/\W+/)
keywords = words.uniq - COMMON_WORDS
{
url: item.path,
id: item[:id],
title: item[:titel],
verkort: item[:verkorte_naam],
konvent: item[:konvent],
body: keywords.join(" ")
}
end.to_a
end
end
def partial_verenigingen
@items.find_all("**/verenigingen/*").map do |x|
{
titel: x[:titel],
url: x.path,
konvent: x[:konvent],
themas: x[:themas],
kind: "vereniging"
}
end
end
def partial_konventen
@items.find_all("**/konventen/*").map do |x|
{
titel: x[:titel],
url: x.path,
kind: "konvent"
}
end
end
end

View file

@ -4,4 +4,5 @@ use_helper Nanoc::Helpers::ChildParent
use_helper NavigationHelper
use_helper VerenigingenHelper
use_helper FontAwesomeHelper
use_helper FontAwesomeHelper
use_helper SearchHelper