Several folks have recently asked me how my “Search site” box works, so here’s a quick writeup on the implementation as it stands at the time of this writing:
The current site is entirely static and is built by calling pandoc
from a
top-level non-recursive site Makefile
, written in GNU
Make.
The main inputs to this Makefile are “pages”, which are
represented as directories each containing a file named index.txt
containing the pandoc
Markdown source for the page.
When run, my Makefile uses find
to locate page directories and then uses pandoc
to convert
the index.txt
page sources into index.html
outputs. Additionally, a tiny script named jsonify.py
, reproduced below:
#!/usr/bin/env python
from __future__ import with_statement
import sys
import cjson
= {}
data
for fn in sys.argv[1:]:
with open(fn) as f:
'index.txt', '')] = f.read()
data[fn.replace(
print cjson.encode(data)
is used to build a target called site.json
containing a JSON-encoded representation of all the source
texts for all the pages in the site indexed by the name of the “page”
directory that contains them.
Next, my Makefile uses pandoc
with a custom HTML template to produce HTML from my page
sources that contains a text input field named #searchbox
(initially hidden by CSS) and that runs the following JavaScript program
during page rendering:
function($){
($(document).ready(function(){
var site;
.getJSON('/site.json', function(data){
$= data;
site $("#searchbar").css("display", "inline-block");
;
})var doSearch;
= function(){
doSearch var search;
= $("#searchbox").val();
search if (search.length > 0) {
var results, pat;
= RegExp(search);
pat = [];
results .each(site, function(k, v){
$if (v.match(pat)) {
.push('<li><a href="/' + k + '">' + v.split(/\n/)[0].replace(/^% /, '') + '</a></li>');
results
};
})if (results.length > 0) {
$("#searchresults").html('<br/><h2>Matching Posts</h2><ul>' + results.join('') + '</ul>');
else {
} $("#searchresults").html('<br/><h2>Matching Posts</h2><p>None</p>');
}
}else {
$("#searchresults").empty();
};
}$("#searchbox").keyup(doSearch);
;})(jQuery); })
When run, this script uses the jQuery library to
asynchronously fetch site.json
, to unhide the searchbox on
success, and to wait for jQuery keyup
events.
keyup
events are then handled by selecting keys from the
previously fetched site
JavaScript object whose values are
matched by the pat
JavaScript
regexp (which was, in turn, built from the value of the
#searchbox
text field).
Finally, the matching object keys are transformed into links and
added to the #searchresults
element’s
innerHTML
.