|
1 | | -// libraries: jquery, lunr, lodash |
2 | | -// arguments: $, lunr, _ |
| 1 | +// libraries: jquery, minisearch, lodash |
| 2 | +// arguments: $, minisearch, _ |
3 | 3 |
|
4 | | -$(document).ready(function () { |
| 4 | +$(function () { |
5 | 5 | // parseUri 1.2.2 |
6 | 6 | // (c) Steven Levithan <stevenlevithan.com> |
7 | 7 | // MIT License |
@@ -54,10 +54,15 @@ $(document).ready(function () { |
54 | 54 | e.preventDefault(); |
55 | 55 | }); |
56 | 56 |
|
| 57 | + let ms_data = documenterSearchIndex["docs"].map((x, key) => { |
| 58 | + x["id"] = key; |
| 59 | + return x; |
| 60 | + }); |
| 61 | + |
57 | 62 | // list below is the lunr 2.1.3 list minus the intersect with names(Base) |
58 | 63 | // (all, any, get, in, is, only, which) and (do, else, for, let, where, while, with) |
59 | 64 | // ideally we'd just filter the original list but it's not available as a variable |
60 | | - lunr.stopWordFilter = lunr.generateStopWordFilter([ |
| 65 | + const stopWords = new Set([ |
61 | 66 | "a", |
62 | 67 | "able", |
63 | 68 | "about", |
@@ -165,114 +170,150 @@ $(document).ready(function () { |
165 | 170 | "your", |
166 | 171 | ]); |
167 | 172 |
|
168 | | - // add . as a separator, because otherwise "title": "Documenter.Anchors.add!" |
169 | | - // would not find anything if searching for "add!", only for the entire qualification |
170 | | - lunr.tokenizer.separator = /[\s\-\.]+/; |
171 | | - |
172 | | - // custom trimmer that doesn't strip @ and !, which are used in julia macro and function names |
173 | | - lunr.trimmer = function (token) { |
174 | | - return token.update(function (s) { |
175 | | - return s.replace(/^[^a-zA-Z0-9@!]+/, "").replace(/[^a-zA-Z0-9@!]+$/, ""); |
176 | | - }); |
177 | | - }; |
| 173 | + let index = new minisearch({ |
| 174 | + fields: ["title", "text"], // fields to index for full-text search |
| 175 | + storeFields: ["location", "title", "text", "category", "page"], // fields to return with search results |
| 176 | + processTerm: (term) => { |
| 177 | + let word = stopWords.has(term) ? null : term; |
| 178 | + if (word) { |
| 179 | + // custom trimmer that doesn't strip @ and !, which are used in julia macro and function names |
| 180 | + word = word |
| 181 | + .replace(/^[^a-zA-Z0-9@!]+/, "") |
| 182 | + .replace(/[^a-zA-Z0-9@!]+$/, ""); |
| 183 | + } |
178 | 184 |
|
179 | | - lunr.Pipeline.registerFunction(lunr.stopWordFilter, "juliaStopWordFilter"); |
180 | | - lunr.Pipeline.registerFunction(lunr.trimmer, "juliaTrimmer"); |
| 185 | + return word ?? null; |
| 186 | + }, |
| 187 | + // add . as a separator, because otherwise "title": "Documenter.Anchors.add!", would not find anything if searching for "add!", only for the entire qualification |
| 188 | + tokenize: (string) => string.split(/[\s\-\.]+/), |
| 189 | + searchOptions: { |
| 190 | + boost: { title: 100 }, |
| 191 | + fuzzy: 2, |
| 192 | + processTerm: (term) => { |
| 193 | + let word = stopWords.has(term) ? null : term; |
| 194 | + if (word) { |
| 195 | + word = word |
| 196 | + .replace(/^[^a-zA-Z0-9@!]+/, "") |
| 197 | + .replace(/[^a-zA-Z0-9@!]+$/, ""); |
| 198 | + } |
181 | 199 |
|
182 | | - var index = lunr(function () { |
183 | | - this.ref("location"); |
184 | | - this.field("title", { boost: 100 }); |
185 | | - this.field("text"); |
186 | | - documenterSearchIndex["docs"].forEach(function (e) { |
187 | | - this.add(e); |
188 | | - }, this); |
| 200 | + return word ?? null; |
| 201 | + }, |
| 202 | + tokenize: (string) => string.split(/[\s\-\.]+/), |
| 203 | + }, |
189 | 204 | }); |
190 | | - var store = {}; |
191 | 205 |
|
192 | | - documenterSearchIndex["docs"].forEach(function (e) { |
193 | | - store[e.location] = { title: e.title, category: e.category, page: e.page }; |
194 | | - }); |
| 206 | + index.addAll(ms_data); |
195 | 207 |
|
196 | | - $(function () { |
197 | | - searchresults = $("#documenter-search-results"); |
198 | | - searchinfo = $("#documenter-search-info"); |
199 | | - searchbox = $("#documenter-search-query"); |
200 | | - searchform = $(".docs-search"); |
201 | | - sidebar = $(".docs-sidebar"); |
202 | | - function update_search(querystring) { |
203 | | - tokens = lunr.tokenizer(querystring); |
204 | | - results = index.query(function (q) { |
205 | | - tokens.forEach(function (t) { |
206 | | - q.term(t.toString(), { |
207 | | - fields: ["title"], |
208 | | - boost: 100, |
209 | | - usePipeline: true, |
210 | | - editDistance: 0, |
211 | | - wildcard: lunr.Query.wildcard.NONE, |
212 | | - }); |
213 | | - q.term(t.toString(), { |
214 | | - fields: ["title"], |
215 | | - boost: 10, |
216 | | - usePipeline: true, |
217 | | - editDistance: 2, |
218 | | - wildcard: lunr.Query.wildcard.NONE, |
219 | | - }); |
220 | | - q.term(t.toString(), { |
221 | | - fields: ["text"], |
222 | | - boost: 1, |
223 | | - usePipeline: true, |
224 | | - editDistance: 0, |
225 | | - wildcard: lunr.Query.wildcard.NONE, |
226 | | - }); |
227 | | - }); |
228 | | - }); |
229 | | - searchinfo.text("Number of results: " + results.length); |
230 | | - searchresults.empty(); |
231 | | - results.forEach(function (result) { |
232 | | - data = store[result.ref]; |
233 | | - link = $('<a class="docs-label">' + data.title + "</a>"); |
234 | | - link.attr("href", documenterBaseURL + "/" + result.ref); |
235 | | - if (data.category != "page") { |
236 | | - cat = $( |
237 | | - '<span class="docs-category">(' + |
238 | | - data.category + |
239 | | - ", " + |
240 | | - data.page + |
241 | | - ")</span>" |
242 | | - ); |
243 | | - } else { |
244 | | - cat = $('<span class="docs-category">(' + data.category + ")</span>"); |
245 | | - } |
246 | | - li = $("<li>").append(link).append(" ").append(cat); |
247 | | - searchresults.append(li); |
248 | | - }); |
249 | | - } |
| 208 | + searchresults = $("#documenter-search-results"); |
| 209 | + searchinfo = $("#documenter-search-info"); |
| 210 | + searchbox = $("#documenter-search-query"); |
| 211 | + searchform = $(".docs-search"); |
| 212 | + sidebar = $(".docs-sidebar"); |
250 | 213 |
|
251 | | - function update_search_box() { |
252 | | - querystring = searchbox.val(); |
253 | | - update_search(querystring); |
254 | | - } |
| 214 | + function update_search(querystring) { |
| 215 | + let results = []; |
| 216 | + results = index.search(querystring, { |
| 217 | + filter: (result) => result.score >= 1, |
| 218 | + }); |
255 | 219 |
|
256 | | - searchbox.keyup(_.debounce(update_search_box, 250)); |
257 | | - searchbox.change(update_search_box); |
| 220 | + searchresults.empty(); |
258 | 221 |
|
259 | | - // Disable enter-key form submission for the searchbox on the search page |
260 | | - // and just re-run search rather than refresh the whole page. |
261 | | - searchform.keypress(function (event) { |
262 | | - if (event.which == "13") { |
263 | | - if (sidebar.hasClass("visible")) { |
264 | | - sidebar.removeClass("visible"); |
| 222 | + let links = []; |
| 223 | + let count = 0; |
| 224 | + |
| 225 | + results.forEach(function (result) { |
| 226 | + if (result.location) { |
| 227 | + if (!links.includes(result.location)) { |
| 228 | + searchresults.append(make_search_result(result, querystring)); |
| 229 | + count++; |
265 | 230 | } |
266 | | - update_search_box(); |
267 | | - event.preventDefault(); |
| 231 | + |
| 232 | + links.push(result.location); |
268 | 233 | } |
269 | 234 | }); |
270 | 235 |
|
271 | | - search_query_uri = parseUri(window.location).queryKey["q"]; |
272 | | - if (search_query_uri !== undefined) { |
273 | | - search_query = decodeURIComponent(search_query_uri.replace(/\+/g, "%20")); |
274 | | - searchbox.val(search_query); |
| 236 | + searchinfo.text("Number of results: " + count); |
| 237 | + } |
| 238 | + |
| 239 | + function make_search_result(result, querystring) { |
| 240 | + let display_link = |
| 241 | + result.location.slice(Math.max(0), Math.min(50, result.location.length)) + |
| 242 | + (result.location.length > 30 ? "..." : ""); |
| 243 | + |
| 244 | + let textindex = new RegExp(`\\b${querystring}\\b`, "i").exec(result.text); |
| 245 | + let text = |
| 246 | + textindex !== null |
| 247 | + ? result.text.slice( |
| 248 | + Math.max(textindex.index - 100, 0), |
| 249 | + Math.min( |
| 250 | + textindex.index + querystring.length + 100, |
| 251 | + result.text.length |
| 252 | + ) |
| 253 | + ) |
| 254 | + : ""; |
| 255 | + |
| 256 | + let display_result = text.length |
| 257 | + ? "..." + |
| 258 | + text.replace( |
| 259 | + new RegExp(`\\b${querystring}\\b`, "i"), // For first occurrence |
| 260 | + '<span class="search-result-highlight p-1">$&</span>' |
| 261 | + ) + |
| 262 | + "..." |
| 263 | + : ""; |
| 264 | + |
| 265 | + let result_div = ` |
| 266 | + <a href="${ |
| 267 | + documenterBaseURL + "/" + result.location |
| 268 | + }" class="search-result-link px-4 py-2 w-100 is-flex is-flex-direction-column gap-2 my-4"> |
| 269 | + <div class="w-100 is-flex is-flex-wrap-wrap is-justify-content-space-between is-align-items-center"> |
| 270 | + <div class="search-result-title has-text-weight-semi-bold">${ |
| 271 | + result.title |
| 272 | + }</div> |
| 273 | + <div class="property-search-result-badge">${result.category}</div> |
| 274 | + </div> |
| 275 | + <p> |
| 276 | + ${display_result} |
| 277 | + </p> |
| 278 | + <div |
| 279 | + class="has-text-left" |
| 280 | + style="font-size: smaller;" |
| 281 | + title="${result.location}" |
| 282 | + > |
| 283 | + <i class="fas fa-link"></i> ${display_link} |
| 284 | + </div> |
| 285 | + </a> |
| 286 | + <div class="search-divider"></div> |
| 287 | + `; |
| 288 | + return result_div; |
| 289 | + } |
| 290 | + |
| 291 | + function update_search_box() { |
| 292 | + querystring = searchbox.val(); |
| 293 | + update_search(querystring); |
| 294 | + } |
| 295 | + |
| 296 | + searchbox.keyup(_.debounce(update_search_box, 250)); |
| 297 | + searchbox.change(update_search_box); |
| 298 | + |
| 299 | + // Disable enter-key form submission for the searchbox on the search page |
| 300 | + // and just re-run search rather than refresh the whole page. |
| 301 | + searchform.keypress(function (event) { |
| 302 | + if (event.which == "13") { |
| 303 | + if (sidebar.hasClass("visible")) { |
| 304 | + sidebar.removeClass("visible"); |
| 305 | + } |
| 306 | + update_search_box(); |
| 307 | + event.preventDefault(); |
275 | 308 | } |
276 | | - update_search_box(); |
277 | 309 | }); |
| 310 | + |
| 311 | + search_query_uri = parseUri(window.location).queryKey["q"]; |
| 312 | + |
| 313 | + if (search_query_uri !== undefined) { |
| 314 | + search_query = decodeURIComponent(search_query_uri.replace(/\+/g, "%20")); |
| 315 | + searchbox.val(search_query); |
| 316 | + } |
| 317 | + |
| 318 | + update_search_box(); |
278 | 319 | }); |
0 commit comments