1/* http://gregfranko.com/blog/jquery-best-practices/ */ 2(function ($) { 3 $(function () { 4 5 $('nav.navbar').headroom(); 6 7 Toc.init({ 8 $nav: $("#toc"), 9 $scope: $("main h2, main h3, main h4, main h5, main h6") 10 }); 11 12 if ($('#toc').length) { 13 $('body').scrollspy({ 14 target: '#toc', 15 offset: $("nav.navbar").outerHeight() + 1 16 }); 17 } 18 19 // Activate popovers 20 $('[data-bs-toggle="popover"]').popover({ 21 container: 'body', 22 html: true, 23 trigger: 'focus', 24 placement: "top", 25 sanitize: false, 26 }); 27 28 $('[data-bs-toggle="tooltip"]').tooltip(); 29 30 /* Clipboard --------------------------*/ 31 32 function changeTooltipMessage(element, msg) { 33 var tooltipOriginalTitle = element.getAttribute('data-bs-original-title'); 34 element.setAttribute('data-bs-original-title', msg); 35 $(element).tooltip('show'); 36 element.setAttribute('data-bs-original-title', tooltipOriginalTitle); 37 } 38 39 if (ClipboardJS.isSupported()) { 40 $(document).ready(function () { 41 var copyButton = "<button type='button' class='btn btn-primary btn-copy-ex' title='Copy to clipboard' aria-label='Copy to clipboard' data-toggle='tooltip' data-placement='left' data-trigger='hover' data-clipboard-copy><i class='fa fa-copy'></i></button>"; 42 43 $("div.sourceCode").addClass("hasCopyButton"); 44 45 // Insert copy buttons: 46 $(copyButton).prependTo(".hasCopyButton"); 47 48 // Initialize tooltips: 49 $('.btn-copy-ex').tooltip({ container: 'body' }); 50 51 // Initialize clipboard: 52 var clipboard = new ClipboardJS('[data-clipboard-copy]', { 53 text: function (trigger) { 54 return trigger.parentNode.textContent.replace(/\n#>[^\n]*/g, ""); 55 } 56 }); 57 58 clipboard.on('success', function (e) { 59 changeTooltipMessage(e.trigger, 'Copied!'); 60 e.clearSelection(); 61 }); 62 63 clipboard.on('error', function (e) { 64 changeTooltipMessage(e.trigger, 'Press Ctrl+C or Command+C to copy'); 65 }); 66 67 }); 68 } 69 70 /* Search marking --------------------------*/ 71 var url = new URL(window.location.href); 72 var toMark = url.searchParams.get("q"); 73 var mark = new Mark("main#main"); 74 if (toMark) { 75 mark.mark(toMark, { 76 accuracy: { 77 value: "complementary", 78 limiters: [",", ".", ":", "/"], 79 } 80 }); 81 } 82 83 /* Search --------------------------*/ 84 /* Adapted from https://github.com/rstudio/bookdown/blob/2d692ba4b61f1e466c92e78fd712b0ab08c11d31/inst/resources/bs4_book/bs4_book.js#L25 */ 85 // Initialise search index on focus 86 var fuse; 87 $("#search-input").focus(async function (e) { 88 if (fuse) { 89 return; 90 } 91 92 $(e.target).addClass("loading"); 93 var response = await fetch($("#search-input").data("search-index")); 94 var data = await response.json(); 95 96 var options = { 97 keys: ["what", "text", "code"], 98 ignoreLocation: true, 99 threshold: 0.1, 100 includeMatches: true, 101 includeScore: true, 102 }; 103 fuse = new Fuse(data, options); 104 105 $(e.target).removeClass("loading"); 106 }); 107 108 // Use algolia autocomplete 109 var options = { 110 autoselect: true, 111 debug: true, 112 hint: false, 113 minLength: 2, 114 }; 115 var q; 116 async function searchFuse(query, callback) { 117 await fuse; 118 119 var items; 120 if (!fuse) { 121 items = []; 122 } else { 123 q = query; 124 var results = fuse.search(query, { limit: 20 }); 125 items = results 126 .filter((x) => x.score <= 0.75) 127 .map((x) => x.item); 128 if (items.length === 0) { 129 items = [{ dir: "Sorry ð¿", previous_headings: "", title: "No results found.", what: "No results found.", path: window.location.href }]; 130 } 131 } 132 callback(items); 133 } 134 $("#search-input").autocomplete(options, [ 135 { 136 name: "content", 137 source: searchFuse, 138 templates: { 139 suggestion: (s) => { 140 if (s.title == s.what) { 141 return `${s.dir} > <div class="search-details"> ${s.title}</div>`; 142 } else if (s.previous_headings == "") { 143 return `${s.dir} > <div class="search-details"> ${s.title}</div> > ${s.what}`; 144 } else { 145 return `${s.dir} > <div class="search-details"> ${s.title}</div> > ${s.previous_headings} > ${s.what}`; 146 } 147 }, 148 }, 149 }, 150 ]).on('autocomplete:selected', function (event, s) { 151 window.location.href = s.path + "?q=" + q + "#" + s.id; 152 }); 153 }); 154})(window.jQuery || window.$) 155 156document.addEventListener('keydown', function (event) { 157 // Check if the pressed key is '/' 158 if (event.key === '/') { 159 event.preventDefault(); // Prevent any default action associated with the '/' key 160 document.getElementById('search-input').focus(); // Set focus to the search input 161 } 162});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.