forked from extern/the-glorious-startpage
140 lines
3.5 KiB
JavaScript
140 lines
3.5 KiB
JavaScript
class AutoSuggestion {
|
|
constructor() {
|
|
this._searchBox = document.querySelector('#searchBox');
|
|
this._suggestionsUL = document.querySelector('#suggestions');
|
|
this._suggestionsContainer = document.querySelector('#suggestionsContainer');
|
|
|
|
this._registerSearchBoxOnKeyUpEvent();
|
|
}
|
|
|
|
hideSuggestions = () => {
|
|
// Hide suggestions
|
|
this._suggestionsContainer.classList.remove('suggestionsShow');
|
|
this._suggestionsUL.innerHTML = '';
|
|
}
|
|
|
|
_showSuggestions = () => {
|
|
// Show suggestions
|
|
this._suggestionsContainer.classList.add('suggestionsShow');
|
|
}
|
|
|
|
// Create input events
|
|
_phraseEvents = button => {
|
|
|
|
// Update searchbox on enter key and mouse click
|
|
button.onkeyup = e => {
|
|
|
|
if (e.key === 'Enter') {
|
|
|
|
this._searchBox.value = button.innerText;
|
|
this._searchBox.focus();
|
|
|
|
} else if (e.key === 'Backspace') {
|
|
|
|
this._searchBox.focus();
|
|
|
|
} else if ((e.key === 'ArrowDown') || e.key === 'ArrowRight') {
|
|
|
|
e.preventDefault();
|
|
|
|
const phraseButtons = Array.prototype.slice.call(document.querySelectorAll('button'));
|
|
const phraseIndex = (phraseButtons.indexOf(document.activeElement) + 1) % phraseButtons.length;
|
|
const phraseButton = phraseButtons[phraseIndex];
|
|
phraseButton.focus();
|
|
|
|
} else if ((e.key === 'ArrowUp') || e.key === 'ArrowLeft') {
|
|
|
|
e.preventDefault();
|
|
|
|
const phraseButtons = Array.prototype.slice.call(document.querySelectorAll('button'));
|
|
const phraseIndex = (phraseButtons.indexOf(document.activeElement) - 1) % phraseButtons.length;
|
|
|
|
if (phraseIndex < 0) {
|
|
phraseIndex = phraseButtons.length - 1;
|
|
};
|
|
|
|
const phraseButton = phraseButtons[phraseIndex];
|
|
phraseButton.focus();
|
|
}
|
|
|
|
}
|
|
|
|
// Onmouseup event
|
|
button.onmouseup = e => {
|
|
this._searchBox.value = button.innerText;
|
|
this._searchBox.focus();
|
|
}
|
|
}
|
|
|
|
// Generate and parse suggestions
|
|
_autocompleteCallback = phrase => {
|
|
|
|
// Filter/parse the objectgerome matil
|
|
const suggestion = phrase.map(i => i.phrase)
|
|
.filter(s => !(s.toLowerCase() === String(this._searchBox.value).toLowerCase()))
|
|
.slice(0, 4);
|
|
|
|
// Empty ul on every callback to refresh list
|
|
this._suggestionsUL.innerHTML = '';
|
|
|
|
// Generate list elements
|
|
for (let phrases of suggestion) {
|
|
|
|
// Create html elements
|
|
const li = document.createElement('li');
|
|
li.id = 'phrase';
|
|
|
|
const button = document.createElement('button');
|
|
button.type = 'button';
|
|
button.className = 'phraseButton';
|
|
button.innerHTML = phrases;
|
|
|
|
// Create input events
|
|
this._phraseEvents(button);
|
|
|
|
// Appent to ul
|
|
li.appendChild(button);
|
|
this._suggestionsUL.appendChild(li);
|
|
}
|
|
|
|
// Show suggestions
|
|
this._showSuggestions();
|
|
}
|
|
|
|
_fetchSuggestion = () => {
|
|
|
|
const endpoint = 'https://duckduckgo.com/ac/';
|
|
const callback = 'autocompleteCallback'
|
|
const searchQuery = String(this._searchBox.value);
|
|
window[callback] = res => {
|
|
// Passed the suggestion object to process it
|
|
this._autocompleteCallback(res);
|
|
}
|
|
|
|
// Fetch from duckduckgo
|
|
const script = document.createElement('script');
|
|
script.type = 'text/javascript';
|
|
script.src = `${endpoint}?callback=${callback}&q=${searchQuery}`;
|
|
document.querySelector('head').appendChild(script);
|
|
}
|
|
|
|
_searchBoxOnKeyUpEvent = e => {
|
|
|
|
if (e.key === 'Tab') return;
|
|
|
|
if (this._searchBox.value < 1) {
|
|
// Hide suggestions
|
|
this.hideSuggestions();
|
|
return;
|
|
}
|
|
|
|
// Fetch suggestion/phrases
|
|
this._fetchSuggestion();
|
|
}
|
|
|
|
_registerSearchBoxOnKeyUpEvent = () => {
|
|
this._searchBox.onkeyup = this._searchBoxOnKeyUpEvent;
|
|
}
|
|
|
|
}
|