gitbook.require(["gitbook", "lodash", "jQuery"], function(gitbook, _, $) { var index = null; var fuse = null; var _search = {engine: 'lunr', opts: {}}; var $searchInput, $searchLabel, $searchForm; var $highlighted = [], hi, hiOpts = { className: 'search-highlight' }; var collapse = false, toc_visible = []; function init(config) { // Instantiate search settings _search = gitbook.storage.get("search", { engine: config.search.engine || 'lunr', opts: config.search.options || {}, }); }; // Save current search settings function saveSearchSettings() { gitbook.storage.set("search", _search); } // Use a specific index function loadIndex(data) { // [Yihui] In bookdown, I use a character matrix to store the chapter // content, and the index is dynamically built on the client side. // Gitbook prebuilds the index data instead: https://github.com/GitbookIO/plugin-search // We can certainly do that via R packages V8 and jsonlite, but let's // see how slow it really is before improving it. On the other hand, // lunr cannot handle non-English text very well, e.g. the default // tokenizer cannot deal with Chinese text, so we may want to replace // lunr with a dumb simple text matching approach. if (_search.engine === 'lunr') { index = lunr(function () { this.ref('url'); this.field('title', { boost: 10 }); this.field('body'); }); data.map(function(item) { index.add({ url: item[0], title: item[1], body: item[2] }); }); return; } fuse = new Fuse(data.map((_data => { return { url: _data[0], title: _data[1], body: _data[2] }; })), Object.assign( { includeScore: true, threshold: 0.1, ignoreLocation: true, keys: ["title", "body"] }, _search.opts )); } // Fetch the search index function fetchIndex() { return $.getJSON(gitbook.state.basePath+"/search_index.json") .then(loadIndex); // [Yihui] we need to use this object later } // Search for a term and return results function search(q) { let results = []; switch (_search.engine) { case 'fuse': if (!fuse) return; results = fuse.search(q).map(function(result) { var parts = result.item.url.split('#'); return { path: parts[0], hash: parts[1] }; }); break; case 'lunr': default: if (!index) return; results = _.chain(index.search(q)).map(function(result) { var parts = result.ref.split("#"); return { path: parts[0], hash: parts[1] }; }) .value(); } // [Yihui] Highlight the search keyword on current page $highlighted = $('.page-inner') .unhighlight(hiOpts).highlight(q, hiOpts).find('span.search-highlight'); scrollToHighlighted(0); return results; } // [Yihui] Scroll the chapter body to the i-th highlighted string function scrollToHighlighted(d) { var n = $highlighted.length; hi = hi === undefined ? 0 : hi + d; // navignate to the previous/next page in the search results if reached the top/bottom var b = hi < 0; if (d !== 0 && (b || hi >= n)) { var path = currentPath(), n2 = toc_visible.length; if (n2 === 0) return; for (var i = b ? 0 : n2; (b && i < n2) || (!b && i >= 0); i += b ? 1 : -1) { if (toc_visible.eq(i).data('path') === path) break; } i += b ? -1 : 1; if (i < 0) i = n2 - 1; if (i >= n2) i = 0; var lnk = toc_visible.eq(i).find('a[href$=".html"]'); if (lnk.length) lnk[0].click(); return; } if (n === 0) return; var $p = $highlighted.eq(hi); $p[0].scrollIntoView(); $highlighted.css('background-color', ''); // an orange background color on the current item and removed later $p.css('background-color', 'orange'); setTimeout(function() { $p.css('background-color', ''); }, 2000); } function currentPath() { var href = window.location.pathname; href = href.substr(href.lastIndexOf('/') + 1); return href === '' ? 'index.html' : href; } // Create search form function createForm(value) { if ($searchForm) $searchForm.remove(); if ($searchLabel) $searchLabel.remove(); if ($searchInput) $searchInput.remove(); $searchForm = $('