Jekyll and Javascript search

Published on 18-07-2015 in [ jekyll, search ]

I have redesigned my personal homepage, once again. It is now using a responsive design, with a Javascript sidebar. And with the help of Ben Howdle's post, I introduced a search function (currently limited to one keyword per query). He offers a full github demo example. However, I had to hack a few things to make it work on this website. So, you can read his post to make it work, and read mine for some minor modifications.

Contrary to Ben Howdle, I decided to have a page dedicated to the search function. So the search form is only accessible from this search page. Obviously, you can follow his example and put the form in the header, so that the user may search at all times.

So, my search page contains both the form and the results part.

1
2
3
4
<form action="/search" method="GET">
  <label for="query">Search:</label>
  <input type="text" name="query" placeholder="Keyword">
</form>

Then, below, the div which will be dynamically populated with the search results.

<div id="results">

</div>

Then, some javascript, to include all the content in the page (it won't be displayed, but it will be searched through). I introduced a nosearch element, which I can include in the header of post, to remove it from the set of searchable posts. And, I also slightly modified a filter for the content, because Ben Howdle's version messed with my content: I introduced | replace: '"', '\"', to properly escape double quotes.

Then, a link to put the search.js in action (see below for the script):

<script src="/js/search.js"></script>

And, finally, a bit of javascript to tell where to put the results (in the results div), and which properties will be useful in the displayed results.

1
2
3
4
5
6
<script>
    new jekyllSearch({
        selector: "#results",
        properties: ["title", "content"]
    });
</script>

I modified the search.js to display results in a way that I liked more (with a mention of the query at the top). This is where you can hack what's displayed for the link in each search result: if you want to include more than the title, you can change the innerHTML line, by adding + " by " + result.author, for instance. You then need to add author: "{{ post.author }}", above, after the JEKYLL_POSTS.push.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 var outputResults = function(results, el, query) {

    <span class="kd">var</span> <span class="nx">frag</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">createDocumentFragment</span><span class="p">();</span>
    <span class="kd">var</span> <span class="nx">requete</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span><span class="s2">"p"</span><span class="p">);</span>
    <span class="nx">requete</span><span class="p">.</span><span class="nx">innerHTML</span> <span class="o">=</span> <span class="s2">"Requête : "</span> <span class="o">+</span> <span class="nx">query</span><span class="p">;</span>
    <span class="nx">frag</span><span class="p">.</span><span class="nx">appendChild</span><span class="p">(</span><span class="nx">requete</span><span class="p">);</span>

    <span class="nx">results</span><span class="p">.</span><span class="nx">forEach</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">result</span><span class="p">)</span> <span class="p">{</span>

        <span class="kd">var</span> <span class="nx">ul</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span><span class="s2">"ul"</span><span class="p">);</span>
        <span class="nx">ul</span><span class="p">.</span><span class="nx">className</span> <span class="o">=</span> <span class="s2">"search-result"</span><span class="p">;</span>

        <span class="kd">var</span> <span class="nx">title</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span><span class="s2">"li"</span><span class="p">);</span>
        <span class="kd">var</span> <span class="nx">link</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span><span class="s2">"a"</span><span class="p">);</span>
        <span class="nx">link</span><span class="p">.</span><span class="nx">href</span> <span class="o">=</span> <span class="nx">result</span><span class="p">.</span><span class="nx">link</span><span class="p">;</span>
        <span class="nx">link</span><span class="p">.</span><span class="nx">innerHTML</span> <span class="o">=</span> <span class="nx">result</span><span class="p">.</span><span class="nx">title</span><span class="p">;</span>
        <span class="nx">title</span><span class="p">.</span><span class="nx">appendChild</span><span class="p">(</span><span class="nx">link</span><span class="p">);</span>

        <span class="nx">ul</span><span class="p">.</span><span class="nx">appendChild</span><span class="p">(</span><span class="nx">title</span><span class="p">);</span>

        <span class="nx">frag</span><span class="p">.</span><span class="nx">appendChild</span><span class="p">(</span><span class="nx">ul</span><span class="p">);</span>

    <span class="p">});</span>

    <span class="nx">el</span><span class="p">.</span><span class="nx">appendChild</span><span class="p">(</span><span class="nx">frag</span><span class="p">);</span>

<span class="p">};</span><span class="w">

And, indeed, you then need to make the following call at (what is now) line 109 in js/search.js (you just pass a third parameter).

        outputResults(this.results, this.el, this.query);