/* http://gregfranko.com/blog/jquery-best-practices/ */ (function($) { $(function() { $('nav.navbar').headroom(); Toc.init({ $nav: $("#toc"), $scope: $("main h2, main h3, main h4, main h5, main h6") }); if ($('#toc').length) { $('body').scrollspy({ target: '#toc', offset: $("nav.navbar").outerHeight() + 1 }); } // Activate popovers $('[data-bs-toggle="popover"]').popover({ container: 'body', html: true, trigger: 'focus', placement: "top", sanitize: false, }); $('[data-bs-toggle="tooltip"]').tooltip(); /* Clipboard --------------------------*/ function changeTooltipMessage(element, msg) { var tooltipOriginalTitle=element.getAttribute('data-original-title'); element.setAttribute('data-original-title', msg); $(element).tooltip('show'); element.setAttribute('data-original-title', tooltipOriginalTitle); } if(ClipboardJS.isSupported()) { $(document).ready(function() { var copyButton = ""; $("div.sourceCode").addClass("hasCopyButton"); // Insert copy buttons: $(copyButton).prependTo(".hasCopyButton"); // Initialize tooltips: $('.btn-copy-ex').tooltip({container: 'body'}); // Initialize clipboard: var clipboard = new ClipboardJS('[data-clipboard-copy]', { text: function(trigger) { return trigger.parentNode.textContent.replace(/\n#>[^\n]*/g, ""); } }); clipboard.on('success', function(e) { changeTooltipMessage(e.trigger, 'Copied!'); e.clearSelection(); }); clipboard.on('error', function() { changeTooltipMessage(e.trigger,'Press Ctrl+C or Command+C to copy'); }); }); } /* Search marking --------------------------*/ var url = new URL(window.location.href); var toMark = url.searchParams.get("q"); var mark = new Mark("main#main"); if (toMark) { mark.mark(toMark, { accuracy: { value: "complementary", limiters: [",", ".", ":", "/"], } }); } /* Search --------------------------*/ /* Adapted from https://github.com/rstudio/bookdown/blob/2d692ba4b61f1e466c92e78fd712b0ab08c11d31/inst/resources/bs4_book/bs4_book.js#L25 */ // Initialise search index on focus var fuse; $("#search-input").focus(async function(e) { if (fuse) { return; } $(e.target).addClass("loading"); var response = await fetch($("#search-input").data("search-index")); var data = await response.json(); var options = { keys: ["what", "text", "code"], ignoreLocation: true, threshold: 0.1, includeMatches: true, includeScore: true, }; fuse = new Fuse(data, options); $(e.target).removeClass("loading"); }); // Use algolia autocomplete var options = { autoselect: true, debug: true, hint: false, minLength: 2, }; var q; async function searchFuse(query, callback) { await fuse; var items; if (!fuse) { items = []; } else { q = query; var results = fuse.search(query, { limit: 20 }); items = results .filter((x) => x.score <= 0.75) .map((x) => x.item); if (items.length === 0) { items = [{dir:"Sorry 😿",previous_headings:"",title:"No results found.",what:"No results found.",path:window.location.href}]; } } callback(items); } $("#search-input").autocomplete(options, [ { name: "content", source: searchFuse, templates: { suggestion: (s) => { if (s.title == s.what) { return `${s.dir} >