summaryrefslogtreecommitdiff
path: root/javascript/live_search.js
blob: 70dea506bfeada25a4a514ac2e3d671cf11d51b8 (plain)
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
(function ($) {
	'use strict';

	/**
	 * LiveSearch - debounced keyup search with JSON results rendered into a container.
	 *
	 * @param {string} inputSel   - jQuery selector for the text input
	 * @param {string} resultsSel - jQuery selector for the results container div
	 * @param {string} url        - endpoint that accepts ?highlight=<term> and returns
	 *                              JSON [{title, href, type}, ...]
	 */
	function LiveSearch(inputSel, resultsSel, url) {
		var $input   = $(inputSel);
		var $results = $(resultsSel);
		var lastVal  = '';
		var minLen   = 3;
		var delay    = 400;
		var timer    = 0;

		if (!$input.length || !$results.length) { return; }

		$input
			.on('focus', function () {
				if (this.value === this.defaultValue) { this.value = ''; }
			})
			.on('blur', function () {
				if (this.value === '') { this.value = this.defaultValue; }
			})
			.on('keyup', function () {
				var val = $.trim($input.val());
				if (val === lastVal) { return; }
				lastVal = val;
				clearTimeout(timer);
				if (val.length >= minLen) {
					$results.text('Searching…');
					timer = setTimeout(doSearch, delay);
				} else {
					$results.empty();
				}
			});

		$input.closest('form').on('submit', function (e) {
			e.preventDefault();
			doSearch();
		});

		function esc(s) {
			return $('<span>').text(s).html();
		}

		function doSearch() {
			var val = $.trim($input.val());
			if (!val || val === $input[0].defaultValue) { return; }
			$.getJSON(url, { highlight: val })
				.done(function (items) {
					if (!items || !items.length) {
						$results.html('<p>No results.</p>');
						return;
					}
					var html = '<ul>';
					$.each(items, function (i, r) {
						html += '<li><a href="' + esc(r.href) + '">' + esc(r.title) + '</a>';
						if (r.type) { html += ' <small>' + esc(r.type) + '</small>'; }
						html += '</li>';
					});
					html += '</ul>';
					$results.html(html);
				})
				.fail(function () {
					$results.html('<p>Search unavailable.</p>');
				});
		}
	}

	window.LiveSearch = LiveSearch;

}(jQuery));