const searchDialog = searchForm.querySelector('dialog');
async function runSearch() {
- const searchTerm = searchInput.value.toLowerCase();
+ const searchTerm = searchInput.value;
let pages = [];
try {
- pages = await window.webidx.search({
- dbfile:'/search.db',
- query: searchTerm,
- });
+ const resp = await fetch(`/search.php?query=${encodeURIComponent(searchTerm)}`);
+ pages = await resp.json();
} catch (error) {
searchDialog.innerHTML = '<strong class="search-category-title">Failed to load search results</strong>';
console.error(error);
}
// Sort pages to prioritise those with word in title
+ const lowerSearchTerm = searchTerm.toLowerCase();
pages.sort((a, b) => {
- const aScore = (a.url.includes(searchTerm) || a.title.toLowerCase().includes(searchTerm)) ? 1 : 0;
- const bScore = (b.url.includes(searchTerm) || b.title.toLowerCase().includes(searchTerm)) ? 1 : 0;
+ const aScore = (a.url.includes(lowerSearchTerm) || a.title.toLowerCase().includes(lowerSearchTerm)) ? 1 : 0;
+ const bScore = (b.url.includes(lowerSearchTerm) || b.title.toLowerCase().includes(lowerSearchTerm)) ? 1 : 0;
return bScore - aScore;
});
const categoryNames = Object.keys(categorised);
for (const page of pages) {
+ let pageCategory = null;
for (const categoryName of categoryNames) {
const category = categorised[categoryName];
- if (page.url.includes(category.filter)) {
- category.pages.push(page);
+ if (page.url.startsWith(category.filter)) {
+ pageCategory = category;
break;
}
}
+ (pageCategory || categorised.other).pages.push(page);
}
const categoryResults = categoryNames.map(name => {
const resultList = categoryResults.length ? categoryResults : [emptyResult];
const results = el('div', {}, resultList);
- for (const child of searchDialog.children) {
- child.remove();
+ while (searchDialog.firstChild) {
+ searchDialog.removeChild(searchDialog.firstChild);
}
searchDialog.append(results);
}
searchDialog.show();
searchInput.focus();
-
+
const clickListener = e => {
- if(!e.target.closest('dialog')) {
+ if (!e.target.closest('dialog')) {
closeListener();
}
};
const escListener = e => {
if (e.key === 'Escape') {
- closeListener();
+ closeListener();
+ }
+ };
+
+ const arrowListener = e => {
+ if (e.key !== 'ArrowDown' && e.key !== 'ArrowUp') {
+ return;
+ }
+ e.preventDefault();
+
+ const links = Array.from(searchDialog.querySelectorAll('a'));
+ const focusables = [searchInput, ...links];
+ if (focusables.length < 2) { // Only search input
+ return;
+ }
+
+ const active = document.activeElement;
+ let currentIndex = focusables.indexOf(active);
+
+ if (e.key === 'ArrowDown') {
+ currentIndex = (currentIndex + 1) % focusables.length;
+ } else { // ArrowUp
+ currentIndex = (currentIndex - 1 + focusables.length) % focusables.length;
}
+
+ focusables[currentIndex].focus();
};
const mouseLeaveListener = e => {
closeListener();
- }
+ };
const closeListener = () => {
searchDialog.close();
document.removeEventListener('click', clickListener);
document.removeEventListener('keydown', escListener);
searchForm.removeEventListener('mouseleave', mouseLeaveListener);
+ searchForm.removeEventListener('keydown', arrowListener);
};
document.addEventListener('click', clickListener);
document.addEventListener('keydown', escListener);
searchForm.addEventListener('mouseleave', mouseLeaveListener);
+ searchForm.addEventListener('keydown', arrowListener);
}
function showSearchLoading() {
showSearchLoading();
runSearch();
}
-})
\ No newline at end of file
+});
+
+
+// Email display
+const emailDisplayLinks = document.querySelectorAll('a.email-display');
+const eb64 = 'ZW1haWxAYm9v' + 'a3N0YWNrYXBwLmNvbQ==';
+for (const link of emailDisplayLinks) {
+ const email = atob(eb64);
+ link.addEventListener('click', e => {
+ e.preventDefault();
+ e.target.textContent = email;
+ e.target.href = 'mailto:' + email;
+ });
+}
\ No newline at end of file