144 lines
4.9 KiB
JavaScript
144 lines
4.9 KiB
JavaScript
import * as params from '@params';
|
|
import Fuse from '../lib/js/fuse-v6.6.2.min.js';
|
|
|
|
async function init() {
|
|
const data = fetch(params.index_url);
|
|
|
|
const search_btn = document.getElementById("search_btn");
|
|
const search_menu_wrapper = document.getElementById("search_menu_wrapper");
|
|
const search_menu_close_btn = document.getElementById("search_menu_close_btn");
|
|
const search_menu_input = document.getElementById("search_menu_input");
|
|
const search_menu_results = document.getElementById("search_menu_results");
|
|
|
|
search_btn.addEventListener("click", function() {
|
|
search_menu_wrapper.classList.remove("hidden");
|
|
search_menu_input.focus();
|
|
});
|
|
|
|
search_menu_close_btn.addEventListener("click", function() {
|
|
search_menu_wrapper.classList.add("hidden");
|
|
});
|
|
|
|
const index_json = await (await data).json();
|
|
const options = {
|
|
distance: 100,
|
|
threshold: 0.3,
|
|
ignoreLocation: true,
|
|
minMatchCharLength: 2,
|
|
keys: [
|
|
'title',
|
|
'permalink',
|
|
'content',
|
|
],
|
|
includeMatches: true,
|
|
};
|
|
const fuse = new Fuse(index_json, options);
|
|
|
|
const createItem = (title, permalink, content) => {
|
|
return `<a href="${permalink}">
|
|
<div class="search-menu-result-item">
|
|
<div class="search-menu-result-item-title">${title}</div>
|
|
<div class="search-menu-result-item-content">${content}</div>
|
|
</div>
|
|
</a>`;
|
|
};
|
|
|
|
const hlItem = (item, matches) => {
|
|
const highlightTitle = (text, match) => {
|
|
let textHl = "", ptr = 0;
|
|
match.forEach(idx => {
|
|
if (ptr < idx[0]) {
|
|
textHl += text.substring(ptr, idx[0]);
|
|
}
|
|
textHl += "<mark>" + text.substring(idx[0], idx[1] + 1) + "</mark>";
|
|
ptr = idx[1] + 1;
|
|
})
|
|
textHl += text.substring(ptr, text.length);
|
|
return textHl;
|
|
};
|
|
|
|
const highlightContent = (text, match) => {
|
|
let textHl = "<mark>" + text.substring(match[0][0], match[0][1] + 1) + "</mark>";
|
|
let ptr = match[0][1] + 1;
|
|
let length = match[0][1] + 1 - match[0][0];
|
|
if (match[0][0] > 0) {
|
|
textHl = "..." + textHl;
|
|
}
|
|
for (let i = 1; i < match.length; i++) {
|
|
const idx = match[i];
|
|
if (ptr < idx[0] && (length + idx[0] - ptr) >= 100) {
|
|
textHl += text.substring(ptr, ptr + (100 - length + 1)) + "...";
|
|
length = 100;
|
|
break;
|
|
}
|
|
|
|
if (ptr < idx[0]) {
|
|
textHl += text.substring(ptr, idx[0]);
|
|
length += idx[0] - ptr;
|
|
}
|
|
textHl += "<mark>" + text.substring(idx[0], idx[1] + 1) + "</mark>";
|
|
length += idx[1] + 1 - idx[0];
|
|
ptr = idx[1] + 1;
|
|
if (length >= 100) {
|
|
break;
|
|
}
|
|
}
|
|
if (length < 100) {
|
|
textHl += text.substring(ptr, ptr + (100 - length));
|
|
}
|
|
if (ptr <= text.length) {
|
|
textHl += "...";
|
|
}
|
|
return textHl;
|
|
}
|
|
|
|
let itemHl = {
|
|
title: undefined,
|
|
permalink: item.permalink,
|
|
content: undefined,
|
|
};
|
|
matches.forEach(match => {
|
|
if (match.key == 'title') {
|
|
itemHl.title = highlightTitle(item.title, match.indices);
|
|
} else if (match.key == 'content') {
|
|
itemHl.content = highlightContent(item.content, match.indices);
|
|
}
|
|
});
|
|
if (itemHl.title === undefined) itemHl.title = item.title;
|
|
if (itemHl.content === undefined) itemHl.content = item.content;
|
|
return itemHl;
|
|
}
|
|
|
|
const buildAllItems = () => {
|
|
search_menu_results.innerHTML = index_json.reduce((acc, curr) => {
|
|
let content = (curr.content.length > 100) ? curr.content.substring(0, 100) + "..." : curr.content;
|
|
return acc + createItem(curr.title, curr.permalink, content);
|
|
}, "");
|
|
};
|
|
|
|
const search = (value) => {
|
|
const results = fuse.search(value);
|
|
|
|
if (results.length == 0) {
|
|
search_menu_results.innerHTML = '';
|
|
} else {
|
|
search_menu_results.innerHTML = results.reduce((acc, curr) => {
|
|
const item = hlItem(curr.item, curr.matches);
|
|
return acc + createItem(item.title, item.permalink, item.content);
|
|
}, "")
|
|
}
|
|
};
|
|
|
|
search_menu_input.addEventListener("input", function() {
|
|
if (this.value === '') {
|
|
buildAllItems();
|
|
} else {
|
|
search(this.value.trim());
|
|
}
|
|
});
|
|
|
|
buildAllItems();
|
|
}
|
|
|
|
window.addEventListener("DOMContentLoaded", init);
|