Skip to content

Commit 6b8368b

Browse files
authored
Improve search logic (#316)
- Display warning when search data is unavailable - Retry downloading search index - Auto-select first option on "enter" press - Remove needless animations Fixes #259
1 parent f251c83 commit 6b8368b

File tree

4 files changed

+74
-45
lines changed

4 files changed

+74
-45
lines changed

_includes/page-core/page-header.html

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,13 @@
7272
<form class="navbar-form navbar-right dropdown" onsubmit="return false;">
7373
<input type="text" id="search-input" class="form-control" placeholder="Quick nav" autocomplete="off" />
7474
<div class="dropdown-menu" id="search-dropdown">
75+
<div class="search-results-container" id="search-no-data-warning">
76+
{% include /style/icon.html type="warning" class="heading-icon" %}
77+
We were unable to retrieve search data from the
78+
server. Make sure that JavaScript is enabled and
79+
that nothing is blocking network access.
80+
</div>
81+
7582
<div class="search-results-container" id="search-results-docs">
7683
<h2>In docs</h2>
7784
<div data-content="docs-results">

_includes/style/icon.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@
55
Parameters:
66

77
type: A name that matches an alert. Valid values are "success", info", "warning" and "danger".
8+
class: A string to be used for additional "class" values (optional)
89

9-
{% endcomment %}{% assign name = include.type %}{% if name == "success" %}{% assign name = "ok" %}{% elsif name == "info" %}{% assign name = "info-sign" %}{% elsif name == "warning" %}{% assign name = "alert" %}{% elsif name == "danger" %}{% assign name = "exclamation-sign" %}{% endif %}<span class="glyphicon glyphicon-{{ name }}" aria-hidden="true"></span>
10+
{% endcomment %}{% assign name = include.type %}{% if name == "success" %}{% assign name = "ok" %}{% elsif name == "info" %}{% assign name = "info-sign" %}{% elsif name == "warning" %}{% assign name = "alert" %}{% elsif name == "danger" %}{% assign name = "exclamation-sign" %}{% endif %}<span class="glyphicon glyphicon-{{ name }} {{ include.class }}" aria-hidden="true"></span>

javascripts/search.js

Lines changed: 62 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
var searchData;
2-
var searchData;
32
var dataLoading = false;
43
var itemLoadTimer, searchKeystrokeEventTimer;
4+
var autoselectedSearchResult = null;
55

66
var projectResultArea, docResultArea, newsResultArea, miscResultArea;
77
$(document).ready(function () {
@@ -11,7 +11,7 @@ $(document).ready(function () {
1111
miscResultArea = $('#search-results-misc > div');
1212

1313
var searchQuery = getQueryParam("search");
14-
if (searchQuery != undefined && searchQuery != "") { //If a search query was provided in the query strings, execute the search
14+
if (searchQuery) { //If a search query was provided in the query strings, execute the search
1515
loadSearchData(function () {
1616
searchUpdate();
1717
});
@@ -29,9 +29,17 @@ $(document).ready(function () {
2929

3030
$('#search-input')
3131
.focus(searchFocus)
32-
.keyup(searchTextChanged);
33-
32+
.keyup(function(event) {
33+
if(event.which == 13) {
34+
if(searchKeystrokeEventTimer == undefined && autoselectedSearchResult)
35+
window.location = autoselectedSearchResult;
36+
return;
37+
}
38+
39+
searchTextChanged()
40+
});
3441

42+
$('#search-no-data-warning').hide();
3543
});
3644

3745
Array.prototype.clean = function (deleteValue) {
@@ -68,24 +76,34 @@ function searchTextChanged() {
6876
}
6977

7078
//Loads the data from the JSON document
71-
function loadSearchData(callback) {
79+
function loadSearchData(callback, numRetries) {
7280
if (dataLoading)
7381
return;
7482

7583
dataLoading = true;
76-
$.getJSON("/search-index.json", function (e) {
84+
$.getJSON("/search-index.json")
85+
.done(function(loadedData) {
7786
dataLoading = false;
78-
searchData = e.slice(0, -1);
87+
searchData = loadedData.slice(0, -1);
88+
for(var dataIndex = 0; dataIndex < searchData.length; dataIndex++) {
89+
searchData[dataIndex].category = searchData[dataIndex].category.split(' ');
90+
}
7991

8092
if (callback != undefined)
8193
callback();
94+
})
95+
.fail(function(error) {
96+
dataLoading = false;
97+
98+
if(numRetries == undefined || numRetries > 0)
99+
loadSearchData(callback, (Number(numRetries) || 3) - 1)
82100
});
83101
}
84102

85103
//Function to actually execute the search (currently only searches title)
86104
function findResults(term) {
87105
if (!searchData)
88-
return undefined;
106+
return null;
89107

90108
//Split by word
91109
var terms = term.toLowerCase().split(/\W/g);
@@ -153,38 +171,45 @@ function doSearch(query) {
153171
newsResultArea.children('.search-result').remove();
154172
miscResultArea.children('.search-result').remove();
155173

156-
//Start the dropdown box's 'open' animation
157-
if (!$('#search-dropdown').is(":visible"))
158-
$('#search-dropdown').slideDown(400, function () {
159-
});
160-
161174
var results = findResults(query);
175+
$('#search-no-data-warning').toggle(!results);
176+
177+
docResultArea.parent().toggle(!!results);
178+
projectResultArea.parent().toggle(!!results);
179+
newsResultArea.parent().toggle(!!results);
180+
miscResultArea.parent().toggle(!!results);
181+
$('#search-dropdown').css('height', results ? '' : 'auto' );
162182

163-
//Load and animate the search results (use good JavaScript practices and do it recursively using acync callbacks)
164-
function loadItem(i) {
165-
var resultArea = miscResultArea;
166-
167-
var categoryTags = results[i].category.split(' ');
168-
if (categoryTags.indexOf('docs') != -1)
169-
resultArea = docResultArea;
170-
else if (categoryTags.indexOf('projects') != -1)
171-
resultArea = projectResultArea;
172-
else if (categoryTags.indexOf('news') != -1)
173-
resultArea = newsResultArea;
174-
175-
resultArea.loadTemplate($('#search-result-template'), results[i], { append: true });
176-
177-
resultArea.children().last().show(20);
178-
179-
if (i < results.length - 1) {
180-
itemLoadTimer = setTimeout(function () {
181-
loadItem(i + 1)
182-
}, 5);
183-
}
183+
//Start the dropdown box's 'open' animation
184+
if (!$('#search-dropdown').is(":visible"))
185+
$('#search-dropdown').slideDown(400);
186+
187+
if(results && results.length > 0) {
188+
autoselectedSearchResult = null;
189+
190+
(function loadItem(startIndex) {
191+
var resultArea = miscResultArea;
192+
193+
var categoryTags = results[startIndex].category;
194+
if (categoryTags.indexOf('docs') != -1)
195+
resultArea = docResultArea;
196+
else if (categoryTags.indexOf('projects') != -1)
197+
resultArea = projectResultArea;
198+
else if (categoryTags.indexOf('news') != -1)
199+
resultArea = newsResultArea;
200+
201+
resultArea.loadTemplate($('#search-result-template'), results[startIndex], { append: true });
202+
203+
if (startIndex < results.length - 1) {
204+
itemLoadTimer = setTimeout(function () {
205+
loadItem(startIndex + 1)
206+
}, 0);
207+
}
208+
else {
209+
autoselectedSearchResult = $('.search-result a').first().attr('href');
210+
}
211+
})(0)
184212
}
185-
186-
if (results.length > 0)
187-
loadItem(0);
188213
}
189214

190215

stylesheets/search.scss

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,9 @@
2626
margin-left: 20px;
2727
}
2828

29-
.search-result {
30-
display: none;
31-
32-
h4 {
33-
font-size: large;
34-
margin-bottom: 0;
35-
}
29+
.search-result h4 {
30+
font-size: large;
31+
margin-bottom: 0;
3632
}
3733

3834
.search-result > div:empty {

0 commit comments

Comments
 (0)