152 lines
4.1 KiB
JavaScript
152 lines
4.1 KiB
JavaScript
import * as preact from "preact";
|
|
import FlexSearch from "flexsearch";
|
|
|
|
import Search from "./Search";
|
|
|
|
/** @jsx preact.h */
|
|
|
|
const originalTitle = document.title;
|
|
|
|
function getURLP(name) {
|
|
const elements = new RegExp(`[?|&]${name}=([^&;]+?)(&|#|;|$)`).exec(
|
|
window.location.search
|
|
);
|
|
|
|
return (
|
|
decodeURIComponent(
|
|
((elements && elements[1]) || "").replace(/\+/g, "%20")
|
|
) || null
|
|
);
|
|
}
|
|
|
|
class SearchEngine {
|
|
constructor(options) {
|
|
this.settings = {
|
|
field: document.getElementById("search_input"),
|
|
show: 10,
|
|
showURL: true,
|
|
showTitleCount: true,
|
|
minimumLength: 3,
|
|
descriptiveWords: 25,
|
|
highlightTerms: true,
|
|
highlightEveryTerm: false,
|
|
contentLocation: "daux_search_index.js",
|
|
...options
|
|
};
|
|
|
|
this.searchIndex = {
|
|
pages: []
|
|
};
|
|
}
|
|
|
|
loadData() {
|
|
if (!this.loadingPromise) {
|
|
// We do this as jsonp instead of an XHR or fetch request
|
|
// to be compatible with usage from filesystem
|
|
const po = document.createElement("script");
|
|
po.type = "text/javascript";
|
|
po.async = true;
|
|
po.src = this.settings.base_url + this.settings.contentLocation;
|
|
const s = document.getElementsByTagName("script")[0];
|
|
s.parentNode.insertBefore(po, s);
|
|
|
|
this.loadingPromise = new Promise(resolve => {
|
|
window.load_search_index = data => resolve(data);
|
|
}).then(json => {
|
|
this.searchIndex = new FlexSearch({
|
|
doc: {
|
|
id: "url",
|
|
field: ["title", "text", "tags"]
|
|
}
|
|
});
|
|
|
|
let pages = json.pages;
|
|
|
|
// Only keep the pages related to the current language
|
|
if (window.searchLanguage) {
|
|
const pagePrefix = `${window.searchLanguage}/`;
|
|
pages = pages.filter(
|
|
item => item.url.indexOf(pagePrefix) === 0
|
|
);
|
|
}
|
|
|
|
this.searchIndex.add(pages);
|
|
});
|
|
}
|
|
|
|
return this.loadingPromise;
|
|
}
|
|
|
|
run() {
|
|
if (getURLP("q")) {
|
|
this.settings.field.value = getURLP("q");
|
|
|
|
this.loadData().then(() => {
|
|
this.displaySearch();
|
|
});
|
|
}
|
|
|
|
this.settings.field.addEventListener("keyup", event => {
|
|
// Start loading index once the user types text in the field, not before
|
|
this.loadData();
|
|
|
|
if (parseInt(event.keyCode, 10) === 13) {
|
|
this.loadData().then(() => {
|
|
this.displaySearch();
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
keyUpHandler = e => {
|
|
if (e.which === 27) {
|
|
//escape
|
|
this.handleClose();
|
|
}
|
|
};
|
|
|
|
handleClose = () => {
|
|
document.title = originalTitle;
|
|
|
|
document.removeEventListener("keyup", this.keyUpHandler);
|
|
|
|
document.body.classList.remove("with-search");
|
|
preact.render(null, this.resultContainer);
|
|
this.resultContainer = null;
|
|
};
|
|
|
|
displaySearch() {
|
|
if (!this.resultContainer) {
|
|
this.resultContainer = document.createElement("div");
|
|
document.body.appendChild(this.resultContainer);
|
|
}
|
|
|
|
document.addEventListener("keyup", this.keyUpHandler);
|
|
|
|
preact.render(
|
|
<Search
|
|
onSearch={term => this.searchIndex.search(term)}
|
|
onClose={this.handleClose}
|
|
onTitleChange={title => {
|
|
document.title = `${title} ${originalTitle}`;
|
|
}}
|
|
settings={this.settings}
|
|
/>,
|
|
this.resultContainer
|
|
);
|
|
|
|
document.body.classList.add("with-search");
|
|
document.body.scrollTop = 0;
|
|
}
|
|
}
|
|
|
|
// Main containers
|
|
|
|
function search(options) {
|
|
const instance = new SearchEngine(options);
|
|
instance.run();
|
|
}
|
|
|
|
// Declare globally
|
|
window.search = search;
|