jf-roku/docs/api/scripts/search.js
2023-11-11 13:41:20 +00:00

266 lines
6.6 KiB
JavaScript

/* global document */
const searchId = 'LiBfqbJVcV';
const searchHash = '#' + searchId;
const searchContainer = document.querySelector('#PkfLWpAbet');
const searchWrapper = document.querySelector('#iCxFxjkHbP');
const searchCloseButton = document.querySelector('#VjLlGakifb');
const searchInput = document.querySelector('#vpcKVYIppa');
const resultBox = document.querySelector('#fWwVHRuDuN');
function showResultText(text) {
resultBox.innerHTML = `<span class="search-result-c-text">${text}</span>`;
}
function hideSearch() {
// eslint-disable-next-line no-undef
if (window.location.hash === searchHash) {
// eslint-disable-next-line no-undef
history.go(-1);
}
// eslint-disable-next-line no-undef
window.onhashchange = null;
if (searchContainer) {
searchContainer.style.display = 'none';
}
}
function listenCloseKey(event) {
if (event.key === 'Escape') {
hideSearch();
// eslint-disable-next-line no-undef
window.removeEventListener('keyup', listenCloseKey);
}
}
function showSearch() {
try {
// Closing mobile menu before opening
// search box.
// It is defined in core.js
// eslint-disable-next-line no-undef
hideMobileMenu();
} catch (error) {
console.error(error);
}
// eslint-disable-next-line no-undef
window.onhashchange = hideSearch;
// eslint-disable-next-line no-undef
if (window.location.hash !== searchHash) {
// eslint-disable-next-line no-undef
history.pushState(null, null, searchHash);
}
if (searchContainer) {
searchContainer.style.display = 'flex';
// eslint-disable-next-line no-undef
window.addEventListener('keyup', listenCloseKey);
}
if (searchInput) {
searchInput.focus();
}
}
async function fetchAllData() {
// eslint-disable-next-line no-undef
const { hostname, protocol, port } = location;
// eslint-disable-next-line no-undef
const base = protocol + '//' + hostname + (port !== '' ? ':' + port : '') + baseURL;
// eslint-disable-next-line no-undef
const url = new URL('data/search.json', base);
const result = await fetch(url);
const { list } = await result.json();
return list;
}
// eslint-disable-next-line no-unused-vars
function onClickSearchItem(event) {
const target = event.currentTarget;
if (target) {
const href = target.getAttribute('href') || '';
let elementId = href.split('#')[1] || '';
let element = document.getElementById(elementId);
if (!element) {
elementId = decodeURI(elementId);
element = document.getElementById(elementId);
}
if (element) {
setTimeout(function() {
// eslint-disable-next-line no-undef
bringElementIntoView(element); // defined in core.js
}, 100);
}
}
}
function buildSearchResult(result) {
let output = '';
const removeHTMLTagsRegExp = /(<([^>]+)>)/ig;
for (const res of result) {
const { title = '', description = '' } = res.item;
const _link = res.item.link.replace('<a href="', '').replace(/">.*/, '');
const _title = title.replace(removeHTMLTagsRegExp, "");
const _description = description.replace(removeHTMLTagsRegExp, "");
output += `
<a onclick="onClickSearchItem(event)" href="${_link}" class="search-result-item">
<div class="search-result-item-title">${_title}</div>
<div class="search-result-item-p">${_description || 'No description available.'}</div>
</a>
`;
}
return output;
}
function getSearchResult(list, keys, searchKey) {
const defaultOptions = {
shouldSort: true,
threshold: 0.4,
location: 0,
distance: 100,
maxPatternLength: 32,
minMatchCharLength: 1,
keys: keys
};
const options = { ...defaultOptions };
// eslint-disable-next-line no-undef
const searchIndex = Fuse.createIndex(options.keys, list);
// eslint-disable-next-line no-undef
const fuse = new Fuse(list, options, searchIndex);
const result = fuse.search(searchKey);
if (result.length > 20) {
return result.slice(0, 20);
}
return result;
}
function debounce(func, wait, immediate) {
let timeout;
return function() {
const args = arguments;
clearTimeout(timeout);
timeout = setTimeout(() => {
timeout = null;
if (!immediate) {
// eslint-disable-next-line consistent-this, no-invalid-this
func.apply(this, args);
}
}, wait);
if (immediate && !timeout) {
// eslint-disable-next-line consistent-this, no-invalid-this
func.apply(this, args);
}
};
}
let searchData;
async function search(event) {
const value = event.target.value;
const keys = ['title', 'description'];
if (!resultBox) {
console.error('Search result container not found');
return;
}
if (!value) {
showResultText('Type anything to view search result');
return;
}
if (!searchData) {
showResultText('Loading...');
try {
// eslint-disable-next-line require-atomic-updates
searchData = await fetchAllData();
} catch (e) {
console.log(e);
showResultText('Failed to load result.');
return;
}
}
const result = getSearchResult(searchData, keys, value);
if (!result.length) {
showResultText('No result found! Try some different combination.');
return;
}
// eslint-disable-next-line require-atomic-updates
resultBox.innerHTML = buildSearchResult(result);
}
function onDomContentLoaded() {
const searchButton = document.querySelectorAll('.search-button');
const debouncedSearch = debounce(search, 300);
if (searchCloseButton) {
searchCloseButton.addEventListener('click', hideSearch);
}
if (searchButton) {
searchButton.forEach(function(item) {
item.addEventListener('click', showSearch);
});
}
if (searchContainer) {
searchContainer.addEventListener('click', hideSearch);
}
if (searchWrapper) {
searchWrapper.addEventListener('click', function(event) {
event.stopPropagation();
});
}
if (searchInput) {
searchInput.addEventListener('keyup', debouncedSearch);
}
// eslint-disable-next-line no-undef
if (window.location.hash === searchHash) {
showSearch();
}
}
// eslint-disable-next-line no-undef
window.addEventListener('DOMContentLoaded', onDomContentLoaded);
// eslint-disable-next-line no-undef
window.addEventListener('hashchange', function() {
// eslint-disable-next-line no-undef
if (window.location.hash === searchHash) {
showSearch();
}
});