7
1
mirror of https://gitlab.com/ansol/web-ansol.org.git synced 2024-11-25 07:33:16 +00:00
web-ansol.org/themes/academic/assets/js/academic-search.js

186 lines
5.8 KiB
JavaScript
Raw Normal View History

2020-06-11 11:46:16 +00:00
/*************************************************
* Academic
* https://github.com/gcushen/hugo-academic
*
* In-built Fuse based search algorithm.
**************************************************/
/* ---------------------------------------------------------------------------
* Configuration.
* --------------------------------------------------------------------------- */
// Configure Fuse.
let fuseOptions = {
shouldSort: true,
includeMatches: true,
tokenize: true,
threshold: search_config.threshold, // Set to ~0.3 for parsing diacritics and CJK languages.
location: 0,
distance: 100,
maxPatternLength: 32,
minMatchCharLength: search_config.minLength, // Set to 1 for parsing CJK languages.
keys: [
{name:'title', weight:0.99}, /* 1.0 doesn't work o_O */
{name:'summary', weight:0.6},
{name:'authors', weight:0.5},
{name:'content', weight:0.2},
{name:'tags', weight:0.5},
{name:'categories', weight:0.5}
]
};
// Configure summary.
let summaryLength = 60;
/* ---------------------------------------------------------------------------
* Functions.
* --------------------------------------------------------------------------- */
// Get query from URI.
function getSearchQuery(name) {
return decodeURIComponent((location.search.split(name + '=')[1] || '').split('&')[0]).replace(/\+/g, ' ');
}
// Set query in URI without reloading the page.
function updateURL(url) {
if (history.replaceState) {
window.history.replaceState({path:url}, '', url);
}
}
// Pre-process new search query.
function initSearch(force, fuse) {
let query = $("#search-query").val();
// If query deleted, clear results.
if ( query.length < 1) {
$('#search-hits').empty();
}
// Check for timer event (enter key not pressed) and query less than minimum length required.
if (!force && query.length < fuseOptions.minMatchCharLength)
return;
// Do search.
$('#search-hits').empty();
searchAcademic(query, fuse);
let newURL = window.location.protocol + "//" + window.location.host + window.location.pathname + '?q=' + encodeURIComponent(query) + window.location.hash;
updateURL(newURL);
}
// Perform search.
function searchAcademic(query, fuse) {
let results = fuse.search(query);
// console.log({"results": results});
if (results.length > 0) {
$('#search-hits').append('<h3 class="mt-0">' + results.length + ' ' + i18n.results + '</h3>');
parseResults(query, results);
} else {
$('#search-hits').append('<div class="search-no-results">' + i18n.no_results + '</div>');
}
}
// Parse search results.
function parseResults(query, results) {
$.each( results, function(key, value) {
let content_key = value.item.section;
let content = "";
let snippet = "";
let snippetHighlights = [];
// Show abstract in results for content types where the abstract is often the primary content.
if (["publication", "talk"].includes(content_key)) {
content = value.item.summary;
} else {
content = value.item.content;
}
if ( fuseOptions.tokenize ) {
snippetHighlights.push(query);
} else {
$.each( value.matches, function(matchKey, matchValue) {
if (matchValue.key == "content") {
let start = (matchValue.indices[0][0]-summaryLength>0) ? matchValue.indices[0][0]-summaryLength : 0;
let end = (matchValue.indices[0][1]+summaryLength<content.length) ? matchValue.indices[0][1]+summaryLength : content.length;
snippet += content.substring(start, end);
snippetHighlights.push(matchValue.value.substring(matchValue.indices[0][0], matchValue.indices[0][1]-matchValue.indices[0][0]+1));
}
});
}
if (snippet.length < 1) {
snippet += value.item.summary; // Alternative fallback: `content.substring(0, summaryLength*2);`
}
// Load template.
let template = $('#search-hit-fuse-template').html();
// Localize content types.
if (content_key in content_type) {
content_key = content_type[content_key];
}
// Parse template.
let templateData = {
key: key,
title: value.item.title,
type: content_key,
relpermalink: value.item.relpermalink,
snippet: snippet
};
let output = render(template, templateData);
$('#search-hits').append(output);
// Highlight search terms in result.
$.each( snippetHighlights, function(hlKey, hlValue){
$("#summary-"+key).mark(hlValue);
});
});
}
function render(template, data) {
// Replace placeholders with their values.
let key, find, re;
for (key in data) {
find = '\\{\\{\\s*' + key + '\\s*\\}\\}'; // Expect placeholder in the form `{{x}}`.
re = new RegExp(find, 'g');
template = template.replace(re, data[key]);
}
return template;
}
/* ---------------------------------------------------------------------------
* Initialize.
* --------------------------------------------------------------------------- */
// If Academic's in-built search is enabled and Fuse loaded, then initialize it.
if (typeof Fuse === 'function') {
// Wait for Fuse to initialize.
$.getJSON(search_config.indexURI, function (search_index) {
let fuse = new Fuse(search_index, fuseOptions);
// On page load, check for search query in URL.
if (query = getSearchQuery('q')) {
$("body").addClass('searching');
$('.search-results').css({opacity: 0, visibility: "visible"}).animate({opacity: 1},200);
$("#search-query").val(query);
$("#search-query").focus();
initSearch(true, fuse);
}
// On search box key up, process query.
$('#search-query').keyup(function (e) {
clearTimeout($.data(this, 'searchTimer')); // Ensure only one timer runs!
if (e.keyCode == 13) {
initSearch(true, fuse);
} else {
$(this).data('searchTimer', setTimeout(function () {
initSearch(false, fuse);
}, 250));
}
});
});
}