From fbf0ea788f582b169366bd550b227078b6678250 Mon Sep 17 00:00:00 2001 From: Mimi <1119186082@qq.com> Date: Mon, 13 Sep 2021 15:07:58 +0800 Subject: [PATCH] Move local-search.js to hexo-generator-searchdb (#369) --- _vendors.yml | 7 + layout/_third-party/search/localsearch.njk | 3 +- source/js/third-party/search/local-search.js | 236 ++----------------- 3 files changed, 23 insertions(+), 223 deletions(-) diff --git a/_vendors.yml b/_vendors.yml index 43d23c7..d931222 100644 --- a/_vendors.yml +++ b/_vendors.yml @@ -138,6 +138,13 @@ instant_search: version: 4.28.0 file: dist/instantsearch.production.min.js integrity: sha256-x+1kTZNP+yy5U5ncci4pes6ALSaVss1UY5hnGy+mfqI= +local_search: + name: hexo-generator-searchdb + version: 1.4.0 + file: dist/search.js + unavailable: + - cdnjs + integrity: sha256-vXZMYLEqsROAXkEw93GGIvaB2ab+QW6w3+1ahD9nXXA= pdfobject: name: pdfobject version: 2.2.6 diff --git a/layout/_third-party/search/localsearch.njk b/layout/_third-party/search/localsearch.njk index e018cc4..8a8d527 100644 --- a/layout/_third-party/search/localsearch.njk +++ b/layout/_third-party/search/localsearch.njk @@ -1 +1,2 @@ -{{- next_js('third-party/search/local-search.js') }} +{{ next_vendors('local_search') }} +{{ next_js('third-party/search/local-search.js') }} diff --git a/source/js/third-party/search/local-search.js b/source/js/third-party/search/local-search.js index 62c9202..a3e5847 100644 --- a/source/js/third-party/search/local-search.js +++ b/source/js/third-party/search/local-search.js @@ -1,4 +1,4 @@ -/* global CONFIG, pjax */ +/* global CONFIG, pjax, LocalSearch */ document.addEventListener('DOMContentLoaded', () => { if (!CONFIG.path) { @@ -6,170 +6,23 @@ document.addEventListener('DOMContentLoaded', () => { console.warn('`hexo-generator-searchdb` plugin is not installed!'); return; } - // Popup Window - let isfetched = false; - let datas; + const localSearch = new LocalSearch({ + path : CONFIG.path, + top_n_per_article: CONFIG.localsearch.top_n_per_article, + unescape : CONFIG.localsearch.unescape + }); + const input = document.querySelector('.search-input'); - const getIndexByWord = (words, text, caseSensitive = false) => { - const index = []; - const included = new Set(); - words.forEach(word => { - if (CONFIG.localsearch.unescape) { - const div = document.createElement('div'); - div.innerText = word; - word = div.innerHTML; - } - const wordLen = word.length; - if (wordLen === 0) return; - let startPosition = 0; - let position = -1; - if (!caseSensitive) { - text = text.toLowerCase(); - word = word.toLowerCase(); - } - while ((position = text.indexOf(word, startPosition)) > -1) { - index.push({ position, word }); - included.add(word); - startPosition = position + wordLen; - } - }); - // Sort index by position of keyword - index.sort((left, right) => { - if (left.position !== right.position) { - return left.position - right.position; - } - return right.word.length - left.word.length; - }); - return [index, included]; - }; - - // Merge hits into slices - const mergeIntoSlice = (start, end, index) => { - let item = index[0]; - let { position, word } = item; - const hits = []; - const count = new Set(); - while (position + word.length <= end && index.length !== 0) { - count.add(word); - hits.push({ - position, - length: word.length - }); - const wordEnd = position + word.length; - - // Move to next position of hit - index.shift(); - while (index.length !== 0) { - item = index[0]; - position = item.position; - word = item.word; - if (wordEnd > position) { - index.shift(); - } else { - break; - } - } - } - return { - hits, - start, - end, - count: count.size - }; - }; - - // Highlight title and content - const highlightKeyword = (val, slice) => { - let result = ''; - let index = slice.start; - for (const { position, length } of slice.hits) { - result += val.substring(index, position); - index = position + length; - result += `${val.substr(position, length)}`; - } - result += val.substring(index, slice.end); - return result; - }; - - const getResultItems = keywords => { - const resultItems = []; - datas.forEach(({ title, content, url }) => { - // The number of different keywords included in the article. - const [indexOfTitle, keysOfTitle] = getIndexByWord(keywords, title); - const [indexOfContent, keysOfContent] = getIndexByWord(keywords, content); - const includedCount = new Set([...keysOfTitle, ...keysOfContent]).size; - - // Show search results - const hitCount = indexOfTitle.length + indexOfContent.length; - if (hitCount === 0) return; - - const slicesOfTitle = []; - if (indexOfTitle.length !== 0) { - slicesOfTitle.push(mergeIntoSlice(0, title.length, indexOfTitle)); - } - - let slicesOfContent = []; - while (indexOfContent.length !== 0) { - const item = indexOfContent[0]; - const { position } = item; - // Cut out 100 characters. The maxlength of .search-input is 80. - const start = Math.max(0, position - 20); - const end = Math.min(content.length, position + 80); - slicesOfContent.push(mergeIntoSlice(start, end, indexOfContent)); - } - - // Sort slices in content by included keywords' count and hits' count - slicesOfContent.sort((left, right) => { - if (left.count !== right.count) { - return right.count - left.count; - } else if (left.hits.length !== right.hits.length) { - return right.hits.length - left.hits.length; - } - return left.start - right.start; - }); - - // Select top N slices in content - const upperBound = parseInt(CONFIG.localsearch.top_n_per_article, 10); - if (upperBound >= 0) { - slicesOfContent = slicesOfContent.slice(0, upperBound); - } - - let resultItem = ''; - - url = new URL(url, location.origin); - url.searchParams.append('highlight', keywords.join(' ')); - - if (slicesOfTitle.length !== 0) { - resultItem += `
${highlightKeyword(content, slice)}...
`; - }); - - resultItem += '