| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183 |
- // Adapted from code by Matt Walters https://www.mattwalters.net/posts/2018-03-28-hugo-and-lunr/
- (function ($) {
- 'use strict';
- $(document).ready(function () {
- const $searchInput = $('.td-search input');
- //
- // Register handler
- //
- $searchInput.on('change', (event) => {
- render($(event.target));
- // Hide keyboard on mobile browser
- $searchInput.blur();
- });
- // Prevent reloading page by enter key on sidebar search.
- $searchInput.closest('form').on('submit', () => {
- return false;
- });
- //
- // Lunr
- //
- let idx = null; // Lunr index
- const resultDetails = new Map(); // Will hold the data for the search results (titles and summaries)
- // Set up for an Ajax call to request the JSON data file that is created by Hugo's build process
- $.ajax($searchInput.data('offline-search-index-json-src')).then((data) => {
- idx = lunr(function () {
- this.ref('ref');
- // If you added more searchable fields to the search index, list them here.
- // Here you can specify searchable fields to the search index - e.g. individual toxonomies for you project
- // With "boost" you can add weighting for specific (default weighting without boost: 1)
- this.field('title', { boost: 5 });
- this.field('categories', { boost: 3 });
- this.field('tags', { boost: 3 });
- // this.field('projects', { boost: 3 }); // example for an individual toxonomy called projects
- this.field('description', { boost: 2 });
- this.field('body');
- data.forEach((doc) => {
- this.add(doc);
- resultDetails.set(doc.ref, {
- title: doc.title,
- excerpt: doc.excerpt,
- });
- });
- });
- $searchInput.trigger('change');
- });
- const render = ($targetSearchInput) => {
- //
- // Dispose existing popover
- //
- {
- let popover = bootstrap.Popover.getInstance($targetSearchInput[0]);
- if (popover !== null) {
- popover.dispose();
- }
- }
- //
- // Search
- //
- if (idx === null) {
- return;
- }
- const searchQuery = $targetSearchInput.val();
- if (searchQuery === '') {
- return;
- }
- const results = idx
- .query((q) => {
- const tokens = lunr.tokenizer(searchQuery.toLowerCase());
- tokens.forEach((token) => {
- const queryString = token.toString();
- q.term(queryString, {
- boost: 100,
- });
- q.term(queryString, {
- wildcard:
- lunr.Query.wildcard.LEADING | lunr.Query.wildcard.TRAILING,
- boost: 10,
- });
- q.term(queryString, {
- editDistance: 2,
- });
- });
- })
- .slice(0, $targetSearchInput.data('offline-search-max-results'));
- //
- // Make result html
- //
- const $html = $('<div>');
- $html.append(
- $('<div>')
- .css({
- display: 'flex',
- justifyContent: 'space-between',
- marginBottom: '1em',
- })
- .append(
- $('<span>').text('Search results').css({ fontWeight: 'bold' })
- )
- .append(
- $('<span>').addClass('td-offline-search-results__close-button')
- )
- );
- const $searchResultBody = $('<div>').css({
- maxHeight: `calc(100vh - ${
- $targetSearchInput.offset().top - $(window).scrollTop() + 180
- }px)`,
- overflowY: 'auto',
- });
- $html.append($searchResultBody);
- if (results.length === 0) {
- $searchResultBody.append(
- $('<p>').text(`No results found for query "${searchQuery}"`)
- );
- } else {
- results.forEach((r) => {
- const doc = resultDetails.get(r.ref);
- const href =
- $searchInput.data('offline-search-base-href') +
- r.ref.replace(/^\//, '');
- const $entry = $('<div>').addClass('mt-4');
- $entry.append(
- $('<small>').addClass('d-block text-body-secondary').text(r.ref)
- );
- $entry.append(
- $('<a>')
- .addClass('d-block')
- .css({
- fontSize: '1.2rem',
- })
- .attr('href', href)
- .text(doc.title)
- );
- $entry.append($('<p>').text(doc.excerpt));
- $searchResultBody.append($entry);
- });
- }
- $targetSearchInput.one('shown.bs.popover', () => {
- $('.td-offline-search-results__close-button').on('click', () => {
- $targetSearchInput.val('');
- $targetSearchInput.trigger('change');
- });
- });
- const popover = new bootstrap.Popover($targetSearchInput, {
- content: $html[0],
- html: true,
- customClass: 'td-offline-search-results',
- placement: 'bottom',
- });
- popover.show();
- };
- });
- })(jQuery);
|