Skip to content

Commit 6fca60a

Browse files
Adding Lunr Search (#403)
Signed-off-by: Nate W <4453979+nate-double-u@users.noreply.github.com>
1 parent 22d68b8 commit 6fca60a

8 files changed

Lines changed: 205 additions & 1 deletion

File tree

‎assets/js/offline-search.js‎

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
// etcd-docsy full file override: we're not tracking changes to the docsy file of the same name.
2+
3+
// Adapted from code by Matt Walters https://www.mattwalters.net/posts/hugo-and-lunr/
4+
5+
(function ($) {
6+
'use strict';
7+
8+
$(document).ready(function () {
9+
const $searchInput = $('.td-search-input');
10+
11+
//
12+
// Options for popover
13+
//
14+
15+
$searchInput.data('html', true);
16+
$searchInput.data('placement', 'bottom');
17+
$searchInput.data(
18+
'template',
19+
'<div class="popover offline-search-result" role="tooltip"><div class="arrow"></div><h3 class="popover-header"></h3><div class="popover-body"></div></div>'
20+
);
21+
22+
//
23+
// Register handler
24+
//
25+
26+
$searchInput.on('change', (event) => {
27+
render($(event.target));
28+
29+
// Hide keyboard on mobile browser
30+
$searchInput.blur();
31+
});
32+
33+
// Prevent reloading page by enter key on sidebar search.
34+
$searchInput.closest('form').on('submit', () => {
35+
return false;
36+
});
37+
38+
//
39+
// Lunr
40+
//
41+
42+
let idx = null; // Lunr index
43+
const resultDetails = new Map(); // Will hold the data for the search results (titles and summaries)
44+
45+
// Set up for an Ajax call to request the JSON data file that is created by Hugo's build process
46+
$.ajax($searchInput.data('offline-search-index-json-src')).then(
47+
(data) => {
48+
idx = lunr(function () {
49+
this.ref('ref');
50+
51+
// If you added more searchable fields to the search index, list them here.
52+
// Here you can specify searchable fields to the search index - e.g. individual toxonomies for you project
53+
// With "boost" you can add weighting for specific (default weighting without boost: 1)
54+
this.field('title', { boost: 5 });
55+
this.field('categories', { boost: 3 });
56+
this.field('tags', { boost: 3 });
57+
// this.field('projects', { boost: 3 }); // example for an individual toxonomy called projects
58+
this.field('description', { boost: 2 });
59+
this.field('body');
60+
61+
data.forEach((doc) => {
62+
this.add(doc);
63+
64+
resultDetails.set(doc.ref, {
65+
title: doc.title,
66+
excerpt: doc.excerpt,
67+
});
68+
});
69+
});
70+
71+
$searchInput.trigger('change');
72+
}
73+
);
74+
75+
const render = ($targetSearchInput) => {
76+
// Dispose the previous result
77+
$targetSearchInput.popover('dispose');
78+
79+
//
80+
// Search
81+
//
82+
83+
if (idx === null) {
84+
return;
85+
}
86+
87+
const searchQuery = $targetSearchInput.val();
88+
if (searchQuery === '') {
89+
return;
90+
}
91+
92+
const results = idx
93+
.query((q) => {
94+
const tokens = lunr.tokenizer(searchQuery.toLowerCase());
95+
tokens.forEach((token) => {
96+
const queryString = token.toString();
97+
q.term(queryString, {
98+
boost: 100,
99+
});
100+
q.term(queryString, {
101+
wildcard:
102+
lunr.Query.wildcard.LEADING |
103+
lunr.Query.wildcard.TRAILING,
104+
boost: 10,
105+
});
106+
q.term(queryString, {
107+
editDistance: 2,
108+
});
109+
});
110+
})
111+
.slice(
112+
0,
113+
$targetSearchInput.data('offline-search-max-results')
114+
);
115+
116+
//
117+
// Make result html
118+
//
119+
120+
const $html = $('<div>');
121+
122+
$html.append(
123+
$('<div>')
124+
.css({
125+
display: 'flex',
126+
justifyContent: 'space-between',
127+
marginBottom: '1em',
128+
})
129+
.append(
130+
$('<span>')
131+
.text('Search results\xa0') // \xa0 is the Non-breakable space char (&nbsp;)
132+
.css({ fontWeight: 'bold' })
133+
)
134+
.append(
135+
$('<i>')
136+
.addClass('fas fa-times search-result-close-button')
137+
.css({
138+
cursor: 'pointer',
139+
})
140+
)
141+
);
142+
143+
const $searchResultBody = $('<div>').css({
144+
maxHeight: `calc(100vh - ${
145+
$targetSearchInput.offset().top -
146+
$(window).scrollTop() +
147+
180
148+
}px)`,
149+
overflowY: 'auto',
150+
});
151+
$html.append($searchResultBody);
152+
153+
if (results.length === 0) {
154+
$searchResultBody.append(
155+
$('<p>').text(`No results found for query "${searchQuery}"`)
156+
);
157+
} else {
158+
results.forEach((r) => {
159+
const doc = resultDetails.get(r.ref);
160+
const href =
161+
$searchInput.data('offline-search-base-href') +
162+
r.ref.replace(/^\//, '');
163+
164+
const $entry = $('<div>').addClass('mt-4');
165+
166+
$entry.append(
167+
$('<small>').addClass('d-block text-muted').text(r.ref)
168+
);
169+
170+
$entry.append(
171+
$('<a>')
172+
.addClass('d-block')
173+
.css({
174+
fontSize: '1.2rem',
175+
})
176+
.attr('href', href)
177+
.text(doc.title)
178+
);
179+
180+
$entry.append($('<p>').text(doc.excerpt));
181+
182+
$searchResultBody.append($entry);
183+
});
184+
}
185+
186+
$targetSearchInput.on('shown.bs.popover', () => {
187+
$('.search-result-close-button').on('click', () => {
188+
$targetSearchInput.val('');
189+
$targetSearchInput.trigger('change');
190+
});
191+
});
192+
193+
$targetSearchInput
194+
.data('content', $html[0].outerHTML)
195+
.popover('show');
196+
};
197+
});
198+
})(jQuery);

‎config.yaml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ params:
7171
algolia_docsearch: false
7272

7373
# Enable Lunr.js offline search
74-
offlineSearch: false
74+
offlineSearch: true
7575

7676
# Enable syntax highlighting and copy buttons on code blocks with Prism
7777
prism_syntax_highlighting: false

‎content/en/docs/v2.3/_index.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ cascade:
44
version: &vers v2.3
55
git_version_tag: v2.3.8
66
is_deprecated: true
7+
exclude_search: true
78
linkTitle: *vers
89
simple_list: true
910
weight: -230

‎content/en/docs/v3.1/_index.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ cascade:
44
version: &vers v3.1
55
git_version_tag: v3.1.20
66
is_deprecated: true
7+
exclude_search: true
78
linkTitle: *vers
89
simple_list: true
910
weight: -310

‎content/en/docs/v3.2/_index.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ cascade:
44
version: &vers v3.2
55
git_version_tag: v3.2.32
66
is_deprecated: true
7+
exclude_search: true
78
linkTitle: *vers
89
simple_list: true
910
weight: -320

‎content/en/docs/v3.3/_index.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ cascade:
44
version: &vers v3.3
55
git_version_tag: v3.3.25
66
is_deprecated: true
7+
exclude_search: true
78
linkTitle: *vers
89
simple_list: true
910
weight: -330

‎content/en/docs/v3.4/_index.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ cascade:
44
version: &vers v3.4
55
git_version_tag: v3.4.16
66
is_deprecated: true
7+
exclude_search: true
78
linkTitle: *vers
89
simple_list: true
910
weight: -340

‎content/en/docs/v3.5/_index.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ cascade:
44
version: v3.5
55
versName: &name v3.5
66
git_version_tag: v3.5.0
7+
exclude_search: false
78
linkTitle: *name
89
simple_list: true
910
weight: -350 # Weight for doc version vX.Y should be -XY0

0 commit comments

Comments
 (0)