fz-search
Version:
Fast aproximate string matching library for use in autocomplete, perform both search and highlight.
318 lines (226 loc) • 10 kB
HTML
<html>
<head lang="en">
<meta charset="UTF-8">
<title>Demo page for FuzzySearch Suggestion engine</title>
<link href="demo.css" rel="stylesheet" type="text/css" />
<script src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
<script src="https://code.jquery.com/ui/1.11.4/jquery-ui.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/typeahead.js/0.11.1/typeahead.jquery.min.js"></script>
<!--script src="../dist/FuzzySearch.min.js"></script-->
<script src="../dist/FuzzySearch.js"></script>
</head>
<body>
<h1>FuzzySearch Demo</h1>
<p>Demo page for <a href="https://github.com/jeancroy/FuzzySearch">FuzzySearch Suggestion engine</a>. </p>
<p>Want a minimal setup demo? it's <a href="simple.html">here</a>. </p>
<h2>Using Twitter Typeahead</h2>
<div class="typeahead">
<input id="demo-query" class="twitter-typeahead" name="demo-query" autocomplete="off" type="text">
</div>
<h2>Using Jquery UI Autocomplete</h2>
<div class="typeahead">
<input id="demo-query-ui-auto" class="twitter-typeahead" name="demo-query-ui-auto" autocomplete="off" type="text">
</div>
<form>
<div style="text-align: left;display:inline-block; width:90%; max-width:450px; margin:auto; clear:both; margin-top:40px">
<strong>Tip!</strong> Your query can match multiple field, for example
"war scalzi" will score in both title and author fields. You can also use <strong>title:</strong> or
<strong>author:</strong> to match a specific field
</div>
<h2>Dataset</h2>
<div style="text-align: left; display:block; width:90%; max-width:500px; margin:auto">
<label><input type="radio" name="source" value="small" checked/> Small book dataset,
<a href="books.json">about 2kb</a>*
</label><br>
<label><input type="radio" name="source" value="medium"/> Medium movie dataset, list of title
<a href="movies.json">about 20kb</a>
</label><br>
<label><input type="radio" name="source" value="large"/> Large book dataset,
<a href="books_large.json">about 220kb</a>
</label><br>
<label><input type="radio" name="source" value="dir"/> Directory dataset (token separated by "/" instead of
spaces),
<a href="dir.json">about 75kb</a>
</label><br>
<label><input type="radio" name="source" value="names30k"/> Name dataset (30K names, using faker.js),
<a href="names30k.json">about 500kb</a>
</label><br>
<label><input type="radio" name="source" value="names100k"/> Name dataset (100K names, using faker.js),
<a href="names100k.json">about 1.6Mb</a>
</label><br>
<br>
<div>
* small book dataset is provided for comparison against a good edit distance implementation <a
href="http://fusejs.io/">fuse.js</a>
</div>
</div>
<h2>Options</h2>
<div style="text-align: left; display:block; width:90%; max-width:500px; margin:auto">
<label><input type="checkbox" name="fused" id="fused"/> Enable score across word "oldmanwar" -> "<b>old man
war</b>" </label><br>
<label><input type="checkbox" name="acro" id="acro"/> Enable acronym score "jrrt" can match <b>J</b>ohn <b>R</b>onald
<b>R</b>euel <b>T</b>olkien </label><br>
<label><input type="checkbox" name="store" id="store"/> Enable Index Store (Can take a few seconds on large data set) </label><br>
</div>
</form>
<!-- allow to scroll so autocomplete is at top of page -->
<div style="height: 500px;"></div>
<script>
//
// Create main object
// We will fill the data once we have the JSON loaded
//
var fuzzyhound = new FuzzySearch({output_limit: 6, output_map:"alias"});
// output_limit: number of item to return
//
// output_map:"alias" : Build a custom output object.
// This can be used to reuse same template with different source format
// Input - Output mapping is set using keys options see "Dataset switch UI" below
// - - - - - - - - - - - - - - - - - - - - - - -
// Item template, shared for both auto-completes
// - - - - - - - - - - - - - - - - - - - - - - -
function itemTemplate(suggestion) {
//This template is the same despite the fact source input change format.
//This is because we use alias option to transform output.
// to make the specific search (title:, author:) work with highlight
// the highlight function take an optional second argument: tag name (alias)
return [
"<div>",
"<span class='title'>\"", fuzzyhound.highlight(suggestion.title,"title"), "\"</span>",
"<span class='author'>", (suggestion.author)? " by " + fuzzyhound.highlight(suggestion.author,"author"): "" , "</span>",
"<span class='score' title='", suggestion._match ,"'>( ", suggestion._score.toFixed(2), " )</span>",
"</div>"
].join("");
}
//
// Use footer to show some performance stats
//
function footerTemplate() {
var render_end = Date.now();
return "<div class='typeahead-footer'> " +
"Search took <strong>" + fuzzyhound.search_time.toFixed(3) + " ms</strong><br>" +
"Total (search+highlight+render): <strong>" + (render_end - fuzzyhound.start_time).toFixed(3) + " ms</strong><br>" +
"Query: <strong>" + fuzzyhound.query.normalized.length + "</strong> chars <br>" +
"Source contain " + fuzzyhound.source.length + " Items<br>" +
"</div>";
}
//- - - - - - - - - - -
// Typeahead Setup
// - - - - - - - - - - -
$('#demo-query').typeahead({
minLength: 2,
highlight: false //we'll use FuzzySearch highlight instead
},
{
name: 'books',
limit: 100, // let fuzzyhound.output_limit apply limit
source: fuzzyhound,
display: "item.title",
templates: {
suggestion: itemTemplate,
footer: footerTemplate,
pending: ""
}
}).bind('typeahead:select', function (ev, suggestion) {
alert('Selection: ' + suggestion.item.title);
});
//- - - - - - - - - - -
// Jquery UI Setup
// - - - - - - - - - - -
var $el = $("#demo-query-ui-auto");
$el.autocomplete({
minLength: 2,
delay: 0, //use FuzzySearch debounce
source: function (request, response) {
response(fuzzyhound.search(request.term));
}
});
//Get instance to extend
var $inst = $el.autocomplete("instance");
//Custom item
$inst._renderItem = function (ul, item) {
return $("<li>").append(itemTemplate(item)).appendTo(ul);
};
//Custom footer
$inst._renderMenu = function (ul, items) {
var nbitems = items.length, i = -1;
while (++i < nbitems) {
var display = items[i].title;
this._renderItem(ul, items[i]).data("ui-autocomplete-item",{display: display, value: display});
}
$("<li>").append(footerTemplate()).data("ui-autocomplete-item", {display: "", value: ""}).appendTo(ul);
};
// - - - - - - - - - - - -
// Setup dataset switch
//- - - - - - - - - - - - -
$.ajaxSetup({cache: true});
function setsource(url, keys) {
$.getJSON(url).then(function (response) {
fuzzyhound.setOptions({
source: response,
keys: keys
})
});
}
//Load small dataset by default
setsource("books.json", ["title", "author"]);
// - - - - - - - - - - - -
// Dataset switch UI
//- - - - - - - - - - - - -
$('input[name=source]:radio').change(function () {
switch (this.value) {
case "large":
setsource("books_large.json", {title:"title", author:"authors.author"} );
break;
case "medium":
setsource("movies.json", {title:"."} ); //Movie is a list of title. Set output.title to the item
break;
case "dir":
setsource("dir.json", {title: "."});
break;
case "names30k":
setsource("names30k.json", {title: "."});
break;
case "names100k":
setsource("names100k.json", {title: "."});
break;
case "small":
default:
setsource("books.json", ["title", "author"]);
break;
}
if (this.value == "dir") {
//directory list use slashes as token separator
fuzzyhound.setOptions({token_sep: "\\/"})
}
else {
//undefined is used as a special value to reset option to default
fuzzyhound.setOptions({token_sep: undefined})
}
});
$('#free').change(function () {
fuzzyhound.setOptions({
score_per_token: $(this).is(":checked")
})
});
$('#fused').change(function () {
fuzzyhound.setOptions({
score_test_fused: $(this).is(":checked")
});
});
$('#acro').change(function () {
fuzzyhound.setOptions({
score_acronym:$(this).is(":checked"),
dirty: true //Acronym building is done at source processing stage so we need to reprocess the source.
});
});
$('#store').change(function () {
fuzzyhound.setOptions({
use_index_store: $(this).is(":checked"),
dirty: true //store is done at source processing stage so we need to reprocess the source.
});
});
</script>
</body>
</html>