Blog




Search is the new sexy

H. Altan Birler

I implemented a new Js Library to add client-side search to tum-sexy. Check it out at https://github.com/hbirler/StaticSearchJs.

tum.sexy is an amazing redirect hub for anything related to TUM Informatics. But since the number of url's on the website was increasing, they wanted a way for the user to search through the url's quickly.

The solution had to be client-side since it is important that the search is responsive and fast (and no one wants to write more php code).

I came up with a general purpose solution, where I traverse the DOM, hiding the elements that do not contain the query and showing the ones that do.

Highlighting helps with quickly recognizing the results.

When you call StaticSearch on the root DOM element that you want to make searchable

let mysearch = staticsearch(document.getElementById("main"));
document.getElementById("searchbox").addEventListener('input', function(evt) {
    let pattern = this.value;
    mysearch.filter(pattern);
});

StaticSearch traverses the elements under the root node and creates a Virtual DOM Tree, extracting the hierarchy and the strings contained within.

The Virtual DOM Tree is later used to efficiently compute the minimum amount of changes required to update the search result. One such optimization is just hiding the topmost element, instead of hiding the children one by one.

Since the library traverses the actual DOM once, the elements under the given root node must be kept static, hence the name StaticSearch.

The library uses the default Js string search by default, but you can supply custom search functions:

//custom search function (regex)
function customGet(pattern, str, single = false) {
    pattern = customPatternTrans(pattern);
    if (pattern == "") return {found:true, values:[]}

    const values = [];

    let match;
    while ((match = pattern.exec(str)) !== null) {
        values.push({start:match.index, end:pattern.lastIndex});
        if (pattern.lastIndex == 0) {
            values = []
            break;
        }

        if (pattern.lastIndex >= str.length || single) {
            break;
        }
    }

    return {found: values.length > 0, values};
}

let mysearch = staticsearch(document.getElementById("main"), {getIndices : customGet});

The library also supports some additional HTML attributes for providing different behavior:

  • data-ss-nofilter: Do not search this node.
  • data-ss-always: Always show this node.
  • data-ss-single: If a child node is shown, the complete node should be shown. Useful in table rows, where a match in a cell causes the whole containing row to * data-ss-additional: If the pattern matches the provided string, the node is shown.
  • data-ss-forceadditional: If the pattern matches the provided string, the node and all its children are shown. Useful for categories, where searching "3. Semester" shows all the lectures that are contained within "3. Semester."

data-ss-forceadditional in use

Here is a demo that demonstrates (almost) all the features:

https://hbirler.github.io/StaticSearchJs/index.html

Feel free to use the library in your own projects. (And please tell me if you do!)

Have fun!