|
| 1 | +(() => { |
| 2 | + fetch('/index.json') |
| 3 | + .then(response => response.json()) |
| 4 | + .then(data => { |
| 5 | + const fuse = new Fuse(data, { |
| 6 | + keys: ['title', 'content'], |
| 7 | + shouldSort: true, |
| 8 | + includeMatches: true, |
| 9 | + minMatchCharLength: 2, |
| 10 | + threshold: 0.0, |
| 11 | + ignoreLocation: true, |
| 12 | + }) |
| 13 | + |
| 14 | + document.getElementById('search-form').addEventListener('submit', function (e) { |
| 15 | + e.preventDefault(); |
| 16 | + const data = new FormData(e.target) |
| 17 | + // data.entries() returns iterator, [...data.entries()] returns [["q", "input"]] |
| 18 | + const input = [...data.entries()][0][1] |
| 19 | + const results = fuse.search(input) |
| 20 | + displayResults(input, results) |
| 21 | + }); |
| 22 | + }); |
| 23 | +})(); |
| 24 | + |
| 25 | +function displayResults(input, results) { |
| 26 | + const searchResults = document.getElementById('search-result'); |
| 27 | + searchResults.setAttribute('style', 'display: block;') |
| 28 | + searchResults.nextElementSibling.setAttribute('style', 'display: none;') |
| 29 | + let html = renderResultsCountHtml(results.length, input) |
| 30 | + if (results.length > 0) { |
| 31 | + let li = renderResultsItemHtml(results) |
| 32 | + html += `<ul>${li}</ul>` |
| 33 | + } |
| 34 | + searchResults.innerHTML = html |
| 35 | +} |
| 36 | + |
| 37 | +function renderResultsCountHtml(count, input) { |
| 38 | + let html = ` |
| 39 | +<div class="TableObject border-gray-light py-3 mt-6"> |
| 40 | + <div class="user-repo-search-results-summary TableObject-item TableObject-item--primary v-align-top"> |
| 41 | + <strong>${count}</strong> |
| 42 | + results |
| 43 | + for "<strong>${input}</strong>" |
| 44 | + </div> |
| 45 | +</div> |
| 46 | +` |
| 47 | + return html |
| 48 | +} |
| 49 | + |
| 50 | +function renderResultsItemHtml(results) { |
| 51 | + // modified from https://github.com/brunocechet/Fuse.js-with-highlight |
| 52 | + var highlighter = function(resultItem){ |
| 53 | + resultItem.matches.forEach((matchItem) => { |
| 54 | + var text = resultItem.item[matchItem.key]; |
| 55 | + var result = [] |
| 56 | + var matches = [].concat(matchItem.indices); |
| 57 | + var pair = matches.shift() |
| 58 | + |
| 59 | + for (var i = 0; i < text.length; i++) { |
| 60 | + var char = text.charAt(i) |
| 61 | + if (pair && i == pair[0]) { |
| 62 | + result.push('<span style="color: red;">') |
| 63 | + } |
| 64 | + result.push(char) |
| 65 | + if (pair && i == pair[1]) { |
| 66 | + result.push('</span>') |
| 67 | + pair = matches.shift() |
| 68 | + } |
| 69 | + } |
| 70 | + resultItem.highlight = result.join(''); |
| 71 | + |
| 72 | + if(resultItem.children && resultItem.children.length > 0){ |
| 73 | + resultItem.children.forEach((child) => { |
| 74 | + highlighter(child); |
| 75 | + }); |
| 76 | + } |
| 77 | + }); |
| 78 | + }; |
| 79 | + |
| 80 | + let html = `` |
| 81 | + results.forEach(result => { |
| 82 | + highlighter(result) |
| 83 | + // truncated highlight content |
| 84 | + let truncated = result.highlight.substring(0, 2000) |
| 85 | + const reg = /(<span style="color: red;">[a-zA-Z0-9\u4e00-\u9fa5]+<\/span>)/g |
| 86 | + let array = truncated.split(reg) |
| 87 | + // drop unstable part |
| 88 | + array.pop() |
| 89 | + let content = "" |
| 90 | + if (array.length > 0) { |
| 91 | + content = array.join('') |
| 92 | + } else { |
| 93 | + // fallback to no highlighted truncated content |
| 94 | + content = result.item.content.substring(0, 2000) |
| 95 | + } |
| 96 | + html += ` |
| 97 | +<li class="col-12 d-flex width-full py-4 border-top color-border-secondary public source"> |
| 98 | + <div class="col-12 d-inline-block"> |
| 99 | + <div class="d-inline-block mb-1"> |
| 100 | + <h3 class="wb-break-all"> |
| 101 | + <a href="${result.item.permalink}">${result.item.title}</a> |
| 102 | + </h3> |
| 103 | + </div> |
| 104 | +
|
| 105 | + <div> |
| 106 | + <div class="col-12 d-inline-block text-gray mb-2 pr-4"> |
| 107 | + ${content} ... |
| 108 | + </div> |
| 109 | + </div> |
| 110 | +
|
| 111 | + </div> |
| 112 | +</li> |
| 113 | +` |
| 114 | + }) |
| 115 | + return html |
| 116 | +} |
0 commit comments