mirror of
https://github.com/Brandon-Rozek/website-theme.git
synced 2024-11-13 20:47:30 -05:00
Merge pull request #17 from koirand/search
Imprement search engine by ngram Close #5
This commit is contained in:
commit
b4e0b7c0c9
4 changed files with 3556 additions and 29 deletions
|
@ -22,6 +22,6 @@
|
||||||
{{ partial "footer.html" . }}
|
{{ partial "footer.html" . }}
|
||||||
<script src="/js/jquery-3.3.1.min.js"></script>
|
<script src="/js/jquery-3.3.1.min.js"></script>
|
||||||
<script src="/js/jquery.mark.es6.min.js"></script>
|
<script src="/js/jquery.mark.es6.min.js"></script>
|
||||||
<script src="/js/fuse.min.js"></script>
|
<script src="/js/lunr.js"></script>
|
||||||
<script src="/js/search.js"></script>
|
<script src="/js/search.js"></script>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
9
static/js/fuse.min.js
vendored
9
static/js/fuse.min.js
vendored
File diff suppressed because one or more lines are too long
3471
static/js/lunr.js
Executable file
3471
static/js/lunr.js
Executable file
File diff suppressed because it is too large
Load diff
|
@ -1,25 +1,87 @@
|
||||||
var fuse
|
var lunrIndex
|
||||||
|
var lunrResult
|
||||||
|
var pagesIndex
|
||||||
|
|
||||||
|
var bigramTokeniser = function (obj, metadata) {
|
||||||
|
if (obj == null || obj == undefined) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(obj)) {
|
||||||
|
return obj.map(function (t) {
|
||||||
|
return new lunr.Token(
|
||||||
|
lunr.utils.asString(t).toLowerCase(),
|
||||||
|
lunr.utils.clone(metadata)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var str = obj.toString().trim().toLowerCase(),
|
||||||
|
tokens = []
|
||||||
|
|
||||||
|
for(var i = 0; i <= str.length - 2; i++) {
|
||||||
|
var tokenMetadata = lunr.utils.clone(metadata) || {}
|
||||||
|
tokenMetadata["position"] = [i, i + 2]
|
||||||
|
tokenMetadata["index"] = tokens.length
|
||||||
|
tokens.push(
|
||||||
|
new lunr.Token (
|
||||||
|
str.slice(i, i + 2),
|
||||||
|
tokenMetadata
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return tokens
|
||||||
|
}
|
||||||
|
|
||||||
|
var queryNgramSeparator = function (query) {
|
||||||
|
var str = query.toString().trim().toLowerCase(),
|
||||||
|
tokens = []
|
||||||
|
|
||||||
|
for(var i = 0; i <= str.length - 2; i++) {
|
||||||
|
tokens.push(str.slice(i, i + 2))
|
||||||
|
}
|
||||||
|
|
||||||
|
return tokens.join(' ')
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Preparation for searching
|
* Preparation for using lunr.js
|
||||||
*/
|
*/
|
||||||
function initSearch () {
|
function initLunr () {
|
||||||
$.getJSON('index.json').done(function (index) {
|
$.getJSON('index.json').done(function (index) {
|
||||||
var options = {
|
pagesIndex = index
|
||||||
shouldSort: true,
|
lunrIndex = lunr(function () {
|
||||||
tokenize: true,
|
this.tokenizer = bigramTokeniser
|
||||||
matchAllTokens: true,
|
this.pipeline.reset()
|
||||||
threshold: 0.3,
|
this.ref('ref')
|
||||||
minMatchCharLength: 5,
|
this.field('title', { boost: 10 })
|
||||||
keys: ['title', 'body']
|
this.field('body')
|
||||||
|
this.metadataWhitelist = ['position']
|
||||||
|
for (var page of pagesIndex) {
|
||||||
|
this.add(page)
|
||||||
}
|
}
|
||||||
fuse = new Fuse(index, options)
|
})
|
||||||
}).fail(function (jqxhr, textStatus, error) {
|
}).fail(function (jqxhr, textStatus, error) {
|
||||||
var err = textStatus + ', ' + error
|
var err = textStatus + ', ' + error
|
||||||
console.error('Error getting Hugo index flie:', err)
|
console.error('Error getting Hugo index flie:', err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searching pages using lunr
|
||||||
|
* @param {String} query Query string for searching
|
||||||
|
* @return {Object[]} Array of search results
|
||||||
|
*/
|
||||||
|
function search (query) {
|
||||||
|
lunrResult = lunrIndex.search(queryNgramSeparator(query))
|
||||||
|
return lunrResult.map(function (result) {
|
||||||
|
return pagesIndex.filter(function (page) {
|
||||||
|
return page.ref === result.ref
|
||||||
|
})[0]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup UI for Search
|
* Setup UI for Search
|
||||||
*/
|
*/
|
||||||
|
@ -33,7 +95,7 @@ function initUI () {
|
||||||
// Event when chenging query
|
// Event when chenging query
|
||||||
$('#searchBoxInput').keyup(function () {
|
$('#searchBoxInput').keyup(function () {
|
||||||
var $searchResults = $('#searchResults')
|
var $searchResults = $('#searchResults')
|
||||||
var query = $(this).val().trim()
|
var query = $(this).val()
|
||||||
|
|
||||||
// Icon switching
|
// Icon switching
|
||||||
if (query.length) {
|
if (query.length) {
|
||||||
|
@ -51,7 +113,7 @@ function initUI () {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Display search results
|
// Display search results
|
||||||
renderResults(fuse.search(query))
|
renderResults(search(query))
|
||||||
$searchResults.show()
|
$searchResults.show()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -66,7 +128,7 @@ function initUI () {
|
||||||
function renderResults (results) {
|
function renderResults (results) {
|
||||||
var $searchResults = $('#searchResults')
|
var $searchResults = $('#searchResults')
|
||||||
var query = $('#searchBoxInput').val()
|
var query = $('#searchBoxInput').val()
|
||||||
var SUMMARY_INCLUDE = 50
|
var BODY_LENGTH = 100
|
||||||
var MAX_PAGES = 10
|
var MAX_PAGES = 10
|
||||||
|
|
||||||
// Clear search result
|
// Clear search result
|
||||||
|
@ -81,10 +143,13 @@ function renderResults (results) {
|
||||||
// Only show the ten first results
|
// Only show the ten first results
|
||||||
results.slice(0, MAX_PAGES).forEach(function (result, idx) {
|
results.slice(0, MAX_PAGES).forEach(function (result, idx) {
|
||||||
var $searchResultPage = $('<div class="searchResultPage">')
|
var $searchResultPage = $('<div class="searchResultPage">')
|
||||||
var matchPosition = result.body.indexOf(query.split(' ')[0])
|
var metadata = lunrResult[idx].matchData.metadata
|
||||||
var bodyStartPosition = matchPosition - SUMMARY_INCLUDE > 0 ? matchPosition - SUMMARY_INCLUDE : 0
|
var matchPosition = metadata[Object.keys(metadata)[0]].body ? metadata[Object.keys(metadata)[0]].body.position[0][0] : 0
|
||||||
|
var bodyStartPosition = (matchPosition - (BODY_LENGTH / 2) > 0) ? matchPosition - (BODY_LENGTH / 2) : 0
|
||||||
|
|
||||||
$searchResultPage.append('<a class="searchResultTitle" href="' + result.ref + '">' + result.title + '</a>')
|
$searchResultPage.append('<a class="searchResultTitle" href="' + result.ref + '">' + result.title + '</a>')
|
||||||
$searchResultPage.append('<div class="searchResultBody">' + result.body.substr(bodyStartPosition, SUMMARY_INCLUDE * 2) + '</div>')
|
|
||||||
|
$searchResultPage.append('<div class="searchResultBody">' + result.body.substr(bodyStartPosition, BODY_LENGTH) + '</div>')
|
||||||
$searchResults.append($searchResultPage)
|
$searchResults.append($searchResultPage)
|
||||||
|
|
||||||
// Highlight keyword
|
// Highlight keyword
|
||||||
|
@ -92,7 +157,7 @@ function renderResults (results) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
initSearch()
|
initLunr()
|
||||||
|
|
||||||
$(function () {
|
$(function () {
|
||||||
initUI()
|
initUI()
|
||||||
|
|
Loading…
Reference in a new issue